On Tuesday, 4 November 2014 at 00:51:10 UTC, H. S. Teoh via Digitalmars-d wrote:
On Mon, Nov 03, 2014 at 04:29:17PM -0800, Walter Bright via Digitalmars-d wrote:
On 11/3/2014 10:03 AM, Nick Treleaven wrote:
>On 02/11/2014 20:33, Walter Bright wrote:
>>It's simply not workable to put a wall between them. Every >>proposal
>>for it has entailed various unfortunate, ugly, and arbitrary
>>consequences.
>
>We need warnings like gcc has:
>
>"-Wsign-compare
> Warn when a comparison between signed and unsigned > values could > produce an incorrect result when the signed value is > converted
>     to unsigned.
>
>-Wconversion
> Warn for implicit conversions that may alter a value. > This > includes ... conversions between signed and unsigned, > like > unsigned ui = -1 ... Warnings about conversions between > signed
>     and unsigned integers can be disabled by using
>     -Wno-sign-conversion.
>"

I find these to suffer from the same problems as all the proposals to
"fix" the issue - they motivate the user to "fix" them with
unfortunate, ugly, and arbitrary consequences.

We need to be very careful with the idea of "just add a warning". Warnings are a sure sign of wishy-washy language design where the designers cannot make up their mind, so they dump it on the user. One person's warning become another person's must fix, and the language
becomes balkanized, which is not good for portability,
comprehensibility, and best practices.
[...]

Don't add a warning, just make it outright illegal to assign signed to unsigned and vice versa unless an explicit cast is given. Code that *needs* to assign signed to unsigned *should* be self-documented with a cast indicating a reinterpretation of the bit representation of the
value, and code that *unintentionally* mixes signs is buggy and
therefore *should* result in a compile error so that the programmer can
fix the problem.

There are no "unfortunate", "ugly", or "arbitrary" consequences here. Much like the recent (or not-so-recent) change of prohibiting implicit conversion of a pointer to bool in an if-condition, or the requirement of a default case in a non-final switch, or so many other improvements in D over C/C++, such a change will (1) make problematic code an error
so that it will get fixed, and (2) force users to rewrite
non-problematic code to be more self-documenting so that their intent is
clearer. Sounds like a win-win situation to me.
Simply change the comparison to something that always works:

/// Returns negative value if a < b, 0 if they are equal or positive value if a > b. /// This will always yield a correct result, no matter which integral types are compared.
/// It uses one extra comparison operation if and only if
/// one type is signed and the other unsigned but has bigger max.
/// For comparison with floating point values the buildin
/// operations have no problem, so we don't handle them here.
C opCmp(T, U)(const(T) a, const(U) b) pure @safe @nogc nothrow if(isIntegral!T && isIntegral!U)
{
   alias Signed!CommonType!(T, U) C;
   static if(isSigned!T && isUnsigned!U && T.sizeof <= U.sizeof)
   {
      return (b > cast(U)T.max) ? -1 : cast(C)a - cast(C)b;
   }
else static if(isUnsigned!T && isSigned!U && T.sizeof >= U.sizeof)
   {
      return (a > cast(T)U.max) ? 1 : cast(C)a - cast(C)b;
   }
else // both signed or both unsigned or the unsigned type is smaller and can therefore be safely cast to the signed type
   {
      return cast(C)a - cast(C)b;
   }
}

Reply via email to