March 19, 2016
On Friday, March 18, 2016 21:17:42 Jonathan M Davis via Digitalmars-d-learn wrote:
> On Friday, March 18, 2016 23:48:32 tsbockman via Digitalmars-d-learn wrote:
> > I'm basically saying, "because information is lost when casting between signed and unsigned, all such casts should be explicit".
>
> See. Here's the fundamental disagreement. _No_ information is lost when converting between signed and unsigned integers. e.g.
>
>     int i = -1;
>     uint ui = i;
>     int j = i;
>     assert(j == -1);
>
> But even if you convinced us, you'd have to convince Walter. And based on previously discussions on this subject, I think that you have an _extremely_ low chance of that. He doesn't even think that there's a problem that
>
> void foo(bool bar) {}
> void foo(long bar) {}
> foo(1);
>
> resulted in call to the bool overload was a problem when pretty much everyone else did. The only thing that I'm aware of that Walter has thought _might_ be something that we should change is allowing the comparison between signed and unsigned integers, and if you read what he says in the bug report for it, he clearly doesn't think it's a big problem:
>
> https://issues.dlang.org/show_bug.cgi?id=259
>
> And that's something that clearly causes bugs in way that converting between signed and unsigned integers does not. You're fighting for a lost cause on this one.

And I really should have proofread this message before sending it... :(

Hopefully, you get what I meant though.

- Jonathan M Davis

March 19, 2016
On Friday, 18 March 2016 at 23:35:42 UTC, tsbockman wrote:
> `ulong.max` and `-1L` are fundamentally different semantically, even with two's complement modular arithmetic.

Different types implies different semantics, but not the literals in isolation.

Under modular arithmetics for an ubyte the literals -128 and 128 both refer to 128. This follows from -128 == 0 - (128). Unfortunately in D, the actual arithmetics is not done modulo 2^8, but modulo 2^32.

So, what we should object to is modular arithmetics over integers as defined in D.

> Just because a few operations (addition and subtraction, mainly) can use a common implementation for both, does not change that. Division, for example, cannot be done correctly without knowing whether the inputs are signed or not.

Yes, both multiplication and division change with the type, but you usually don't want signed values in modular arithmetics?

The major flaw is in how D defines arithmetics for integers.

March 19, 2016
On Saturday, 19 March 2016 at 04:17:42 UTC, Jonathan M Davis wrote:
> The only thing that I'm aware of that Walter has thought _might_ be something that we should change is allowing the comparison between signed and unsigned integers, and if you read what he says in the bug report for it, he clearly doesn't think it's a big problem:
>
> https://issues.dlang.org/show_bug.cgi?id=259
>
> And that's something that clearly causes bugs in way that converting between signed and unsigned integers does not. You're fighting for a lost cause on this one.
>
> - Jonathan M Davis

You do realize that, technically, there are no comparisons between basic signed and unsigned integers in D? The reason that *attempting* such a comparison produces such weird results, is because the signed value is being implicitly cast to an unsigned type.

The thing you say *is* a problem, is directly caused by the thing that you say is *not* a problem.
March 19, 2016
On Saturday, 19 March 2016 at 08:49:29 UTC, Ola Fosheim Grøstad wrote:
> On Friday, 18 March 2016 at 23:35:42 UTC, tsbockman wrote:
>> `ulong.max` and `-1L` are fundamentally different semantically, even with two's complement modular arithmetic.
>
> Different types implies different semantics, but not the literals in isolation.

Both of the literals I used in my example explicitly indicate the type, not just the value.

March 19, 2016
On Saturday, 19 March 2016 at 09:35:00 UTC, tsbockman wrote:
> Both of the literals I used in my example explicitly indicate the type, not just the value.

Yes, but few people specify unsigned literals and relies on them being implicitly cast to unsigned. You don't want to type 0UL and 1UL all the time. This is a another thing that Go does better, numeric literals ought to not be bound to a concrete type. So while I agree with you that the integer situation is messy, changing it to something better requires many changes. Which I am all for.


March 19, 2016
On Saturday, 19 March 2016 at 09:33:25 UTC, tsbockman wrote:
> [...] The reason that *attempting* such a comparison produces such weird results, is because the signed value is being implicitly cast to an unsigned type.

Yes and that's the opposite that should happend: when signed and unsigned are mixed in a comparison, the unsigned value should be implictly cast to a wider signed value. And then it works!

- https://issues.dlang.org/show_bug.cgi?id=15805
- https://github.com/BBasile/iz/blob/v0.5.8/import/iz/sugar.d#L1017


March 19, 2016
On Saturday, 19 March 2016 at 10:01:41 UTC, Basile B. wrote:
> On Saturday, 19 March 2016 at 09:33:25 UTC, tsbockman wrote:
>> [...] The reason that *attempting* such a comparison produces such weird results, is because the signed value is being implicitly cast to an unsigned type.
>
> Yes and that's the opposite that should happend: when signed and unsigned are mixed in a comparison, the unsigned value should be implictly cast to a wider signed value. And then it works!
>
> - https://issues.dlang.org/show_bug.cgi?id=15805
> - https://github.com/BBasile/iz/blob/v0.5.8/import/iz/sugar.d#L1017

I have no problem with C++ compilers complaining about signed/unsigned comparisons. It sometimes means you should reconsider the comparison, so it leads to better code.

The better solution is to add 7, 15, 31 and 63 bit unsigned integer types that safely converts to signed (this is what Ada does) and remove implicit conversion for unsigned 8,16,32, and 64 bit integers.

March 19, 2016
On Saturday, 19 March 2016 at 10:24:41 UTC, Ola Fosheim Grøstad wrote:
> On Saturday, 19 March 2016 at 10:01:41 UTC, Basile B. wrote:
>> On Saturday, 19 March 2016 at 09:33:25 UTC, tsbockman wrote:
>>> [...] The reason that *attempting* such a comparison produces such weird results, is because the signed value is being implicitly cast to an unsigned type.
>>
>> Yes and that's the opposite that should happend: when signed and unsigned are mixed in a comparison, the unsigned value should be implictly cast to a wider signed value. And then it works!
>>
>> - https://issues.dlang.org/show_bug.cgi?id=15805
>> - https://github.com/BBasile/iz/blob/v0.5.8/import/iz/sugar.d#L1017
>
> I have no problem with C++ compilers complaining about signed/unsigned comparisons. It sometimes means you should reconsider the comparison, so it leads to better code.
>
> The better solution is to add 7, 15, 31 and 63 bit unsigned integer types that safely converts to signed (this is what Ada does)

FPC (Object Pascal) too, but that not a surpise since it's in the same family

> and remove implicit conversion for unsigned 8,16,32, and 64 bit integers.

Yes that's almost that but in D the only solution I see is like in my template: widening. When widening is not possible (mainly on X86_64) then warning. The problem is that cent and ucent are not implemented, otherwise it would always work even on 64 bit OS.

I'd like to propose  a PR for this (not for cent/ucent but for the widening) but it looks a bit overcomplicated for a first contrib in the compiler...
March 19, 2016
On Saturday, 19 March 2016 at 10:01:41 UTC, Basile B. wrote:
> Yes and that's the opposite that should happend: when signed and unsigned are mixed in a comparison, the unsigned value should be implictly cast to a wider signed value. And then it works!

That would be reasonable. Whether it's actually faster than just inserting an extra check for `signed_value < 0` in mixed comparisons is likely platform dependent, though.

Honestly though - even just changing the rules to implicitly convert both operands to a signed type of the same size, instead of an unsigned type of the same size, would be a huge improvement. Small negative values are way more common than huge (greater than signed_type.max) positive ones in almost all code. (This change will never happen, of course, as it would be far too subtle of a breaking change for existing code.)

Regardless, the first step is to implement the pre-approved solution to DMD 259: deprecate the current busted behavior.
March 21, 2016
On 3/18/16 7:48 PM, tsbockman wrote:
> On Friday, 18 March 2016 at 14:51:34 UTC, Steven Schveighoffer wrote:
>> Note, I have made these mistakes myself, and I understand what you are
>> asking for and why you are asking for it. But these are bugs. The user
>> is telling the compiler to do one thing, and expecting it to do
>> something else. It's not difficult to fix, and in fact, many lines of
>> code are written specifically to take advantage of these rules. This
>> is why we cannot remove them. The benefit is not worth the cost.
>
> Actually, I think I confused things for you by mentioning to `cast(ulong)`.
>
> I'm not asking for a Java-style "no unsigned" system (I hate that; it's
> one of my biggest annoyances with Java). Rather, I'm picking on
> *implicit* conversions between signed and unsigned.

No, I understood you meant implicit casting.

>
> I'm basically saying, "because information is lost when casting between
> signed and unsigned, all such casts should be explicit". This could make
> code rather verbose - except that from my experiments, with decent VRP
> the compiler can actually be surprisingly smart about warning only in
> those cases where implicit casting is really a bad idea.

Your definition of when "implicit casting is really a bad idea" is almost certainly going to include cases where it really isn't a bad idea. The compiler isn't all-knowing, and there will always be cases where the user knows best (and did the conversion intentionally).

An obvious one is:

void foo(ubyte[] x)
{
  int len = x.length;
}

(let's assume 32-bit CPU) I'm assuming the compiler would complain about this, since technically, len could be negative! Disallowing such code or requiring a cast is probably too much.

-Steve