On Wednesday, 12 December 2012 at 00:51:19 UTC, Walter Bright wrote:
On 12/11/2012 3:44 PM, foobar wrote:
Thanks for proving my point. after all , you are a C++ developer, aren't you? :)

No, I'm an assembler programmer. I know how the machine works, and C, C++, and D map onto that, quite deliberately. It's one reason why D supports the vector types directly.


Seriously though, it _is_ a trick and a code smell.

Not to me. There is no trick or "smell" to anyone familiar with how computers work.


I'm fully aware that computers used 2's complement. I'm also am aware of the fact that the type has an "unsigned" label all over it. You see it right there in that 'u' prefix of 'int'. An unsigned type should semantically entail _no sign_ in its operations. You are calling a cat a dog and arguing that dogs barf? Yeah, I completely agree with that notion, except, we are still talking about _a
cat_.

Andrei and I have endlessly talked about this (he argued your side). The inevitable result is that signed and unsigned types *are* conflated in D, and have to be, otherwise many things stop working.

For example, p[x]. What type is x?

Integer signedness in D is not really a property of the data, it is only how one happens to interpret the data in a specific context.


To answer you question, yes, I would enforce overflow and underflow checking semantics. Any negative result assigned to an unsigned type _is_ a logic error.
you can claim that:
uint a = -1;
is perfectly safe and has a well defined meaning (well, for C programmers that
is), but what about:
uint a = b - c;
what if that calculation results in a negative number? What should the compiler
do? well, there are _two_ equally possible solutions:
a. The overflow was intended as in the mask = -1 case; or
b. The overflow is a _bug_.

The user should be made aware of this and should make the decision how to handle this. This should _not_ be implicitly handled by the compiler and allow bugs go
unnoticed.

I think C# solved this _way_ better than C/D.

C# has overflow checking off by default. It is enabled by either using a checked { } block, or with a compiler switch. I don't see that as "solving" the issue in any elegant or natural way, it's more of a clumsy hack.

But also consider that C# does not allow pointer arithmetic, or array slicing. Both of these rely on wraparound 2's complement arithmetic.


Another data point would be (S)ML
which is a compiled language which requires _explicit conversions_ and has a very strong typing system. Its programs are compiled to efficient native executables and the strong typing allows both the compiler and the programmer better reasoning of the code. Thus programs are more correct and can be optimized by the compiler. In fact, several languages are implemented in ML
because of its higher guaranties.

ML has been around for 30-40 years, and has failed to catch on.

This is precisely the point that signed and unsigned types are conflated *in D*.
Other languages, namely ML chose a different design.
ML chose to have two distinct types: word and int, word is for binary data and int for integer numbers. Words provide efficient access to the machine representation and have no overflow checks, ints represent numbers and do carry overflow checks. you can convert between the two and the compiler/run-time can carry special knowledge about such conversions in order to provide better optimization. in ML, array indexing is done with an int since it _is_ conceptually a number.

Btw, SML was standardized in '97. I'll also dispute the claim that it hasn't caught on - there are many derived languages from it and it is just as large if not larger than the C family of languages. It has influenced many languages and it and its derivations are being used. One example that comes to mind is the future version of JavaScript is implemented in ML. So no, not forgotten but rather alive and kicking.

Reply via email to