View mode: basic / threaded / horizontal-split · Log in · Help
February 16, 2010
Re: disabling unary "-" for unsigned types
On Mon, 15 Feb 2010 19:29:27 -0500, Michel Fortin  
<michel.fortin@michelf.com> wrote:

> On 2010-02-15 18:33:11 -0500, "Steven Schveighoffer"  
> <schveiguy@yahoo.com> said:
>
>> I should clarify, using - on an unsigned value should work, it just  
>> should
>> not be assignable to an unsigned type.  I guess I disagree with the
>> original statement for this post (that it should be disabled all
>> together), but I think that the compiler should avoid something that is
>> 99% of the time an error.
>>  i.e.
>>  uint a = -1; // error
>> uint b = 5;
>> uint c = -b; // error
>> int d = -b; // ok
>> auto e = -b; // e is type int
>
> But should this work?
>
> uint a = 0-1;
> uint c = 0-b;
> auto e = 0-b; // e is type int?

Through integer promotion rules, these all work.  This is essentially  
negation, but it is not a unary operation.  These could also be  
disallowed, but only after optimization.  Because optimizing cannot change  
the semantic meaning, they have to be allowed.

That is typeof(uint - uint) is uint, no matter how you do it.

unary negation is a different operator.

>
> uint zero = 0;
> uint a = zero-1;
> uint c = zero-b;
> auto e = zero-b; // e is type int?

No different than your first examples.  e is of type uint, since uint -  
uint = uint.

> This rule has good intentions, but it brings some strange  
> inconsistencies. The current rules are much easier to predict since they  
> behave always the same whether you have a variable, a literal or a  
> constant expression.

There are plenty of strange inconsistencies in all aspects of computer  
math.  but unary negation of an unsigned value to get another unsigned  
value is one of those inconsistencies that is 99% of the time not what the  
user expected, and easily flagged as an error.

For example, there is no possible way a person unfamiliar with computers  
(and most programmers who have not run into this) would believe that

b = 5;
a = -b;

would result in a being some large positive number.  It's just totally  
unexpected, and totally avoidable.

-Steve
February 16, 2010
Re: disabling unary "-" for unsigned types
On Mon, 15 Feb 2010 21:32:21 -0500, Rainer Deyke <rainerd@eldwood.com>  
wrote:

> Ellery Newcomer wrote:
>> On 02/15/2010 05:33 PM, Steven Schveighoffer wrote:
>>> uint a = -1; // error
>>
>> I can't say I would appreciate having to write
>>
>> uint a = 0xFFFFFFFF;
>>
>> or the equivalent for ulong.
>
> uint a = ~0u;

even ~0 works, no need for the u (although it makes things clearer).

Ellery, you didn't read my original post thoroughly, I said this was the  
most common case of wanting to use unary negative on an unsigned value,  
and it's easily rewritten, with the same number of characters no less.

-Steve
February 16, 2010
Re: disabling unary "-" for unsigned types
On Mon, 15 Feb 2010 17:21:09 -0500, Walter Bright  
<newshound1@digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> are there any good cases besides this that Walter has?  And even if  
>> there are, we are not talking about silently mis-interpreting it.   
>> There is precedent for making valid C code an error because it is error  
>> prone.
>
>
> Here's where I'm coming from with this. The problem is that CPU integers  
> are 2's complement and a fixed number of bits. We'd like to pretend they  
> work just like whole numbers we learned about in 2nd grade arithmetic.  
> But they don't, and we can't fix it so they do. I think it's ultimately  
> fruitless to try and make them behave other than what they are: 2's  
> complement fixed arrays of bits.
>
> So, we wind up with oddities like overflow, wrap-around,  
> -int.min==int.min. Heck, we *rely* on these oddities (subtraction  
> depends on wrap-around). Sometimes, we pretend these bit values are  
> signed, sometimes unsigned, and we mix together those notions in the  
> same expression.

One further thing I'll say on this:

signed computer math makes a lot of sense to people because the limits are  
so large.  For instance, -2 billion to 2 billion.  It seems logical that a  
computer can't just keep coming up with new bits to represent numbers, but  
it seems so far off that an integer will wrap at 2 billion.  But unsigned  
math has a much more familiar boundary -- zero.  Numbers are far more  
likely to be near zero than they are near 2 billion or -2 billion.   
Applying a negation operator to an unsigned value almost *guarantees*  
wrapping past that boundary.  99% of the time, when I apply a negative  
sign to a number, I want the negative equivalent of that number.  I don't  
want some large bizarre value that has no relation to that number, despite  
what the computer thinks is sane.  I'd look at applying a negation  
operator to an unsigned int with as much scrutiny as I'd look at  
multiplying an integer by 1_000_000_000.  It's almost guaranteed to go out  
of bounds, why are you doing it?

Bringing up -int.min == int.min is exactly my point.  For integers, there  
is one value that the negation operator doesn't work as expected.  For  
unsigned integers, there is only one number that *does* work as expected  
-- zero.  All others either don't work as expected, or rely on the  
computer behaving strangely (if it is indeed expected).  To make such rare  
purposeful uses more explicit does not lower the quality of code or the  
ease of use.

-Steve
February 16, 2010
Re: disabling unary "-" for unsigned types
On 02/15/2010 09:17 PM, Steven Schveighoffer wrote:
> On Mon, 15 Feb 2010 21:32:21 -0500, Rainer Deyke <rainerd@eldwood.com>
> wrote:
>
>> Ellery Newcomer wrote:
>>> On 02/15/2010 05:33 PM, Steven Schveighoffer wrote:
>>>> uint a = -1; // error
>>>
>>> I can't say I would appreciate having to write
>>>
>>> uint a = 0xFFFFFFFF;
>>>
>>> or the equivalent for ulong.
>>
>> uint a = ~0u;
>
> even ~0 works, no need for the u (although it makes things clearer).
>
> Ellery, you didn't read my original post thoroughly, I said this was the
> most common case of wanting to use unary negative on an unsigned value,
> and it's easily rewritten, with the same number of characters no less.
>
> -Steve

Ohhh! that post! You're right; I missed that part.

Alright, here's something I found myself writing just today or yesterday:

//x,r are long, n is ulong

if(x < 0){
  ulong ux = -x;
  ...
}

I also have

if(r < 0){
  return n - (-r) % n;
}

emphasis on ensuring dividend is positive before it gets promoted to 
ulong, etc etc, and I do guard that r is not remotely close to 
ulong.max/min.

assuming that the return type is long (it isn't, but it might as well 
be, since n is always within [2,long.max]) or gets assigned to long or 
whatever.

-The bottom one obeys your rules.
-The top one doesn't.
-The bottom one is much less clear than the top.
-Whatever I was trying to prove, I think I just inadvertently 
strengthened your argument tenfold.

and no, I expect this doesn't fall within the 99% use case of unary -
February 16, 2010
Re: disabling unary "-" for unsigned types
On 02/15/2010 11:35 PM, Ellery Newcomer wrote:
> On 02/15/2010 09:17 PM, Steven Schveighoffer wrote:
>> On Mon, 15 Feb 2010 21:32:21 -0500, Rainer Deyke <rainerd@eldwood.com>
>> wrote:
>>
>>> Ellery Newcomer wrote:
>>>> On 02/15/2010 05:33 PM, Steven Schveighoffer wrote:
>>>>> uint a = -1; // error
>>>>
>>>> I can't say I would appreciate having to write
>>>>
>>>> uint a = 0xFFFFFFFF;
>>>>
>>>> or the equivalent for ulong.
>>>
>>> uint a = ~0u;
>>
>> even ~0 works, no need for the u (although it makes things clearer).
>>
>> Ellery, you didn't read my original post thoroughly, I said this was the
>> most common case of wanting to use unary negative on an unsigned value,
>> and it's easily rewritten, with the same number of characters no less.
>>
>> -Steve
>
> Ohhh! that post! You're right; I missed that part.
>
> Alright, here's something I found myself writing just today or yesterday:
>
> //x,r are long, n is ulong
>
> if(x < 0){
> ulong ux = -x;
> ...
> }
>
> I also have
>
> if(r < 0){
> return n - (-r) % n;
> }
>
> emphasis on ensuring dividend is positive before it gets promoted to
> ulong, etc etc, and I do guard that r is not remotely close to
> ulong.max/min.
>
> assuming that the return type is long (it isn't, but it might as well
> be, since n is always within [2,long.max]) or gets assigned to long or
> whatever.
>
> -The bottom one obeys your rules.
> -The top one doesn't.
> -The bottom one is much less clear than the top.
> -Whatever I was trying to prove, I think I just inadvertently
> strengthened your argument tenfold.
>
> and no, I expect this doesn't fall within the 99% use case of unary -

Oh, darn it. nvm
February 16, 2010
Re: disabling unary "-" for unsigned types
Steven Schveighoffer wrote:
> For example, there is no possible way a person unfamiliar with computers 

That's a valid argument if you're writing a spreadsheet program. But 
programmers should be familiar with computers, and most definitely 
should be familiar with 2's complement arithmetic.

Similarly, if you do much with floating point, you should be familiar 
with "What Every Computer Scientist Should Know About Floating-Point 
Arithmetic"

http://docs.sun.com/source/806-3568/ncg_goldberg.html
February 16, 2010
Re: disabling unary "-" for unsigned types
Walter Bright wrote:

> Steven Schveighoffer wrote:
>> For example, there is no possible way a person unfamiliar with computers
> 
> That's a valid argument if you're writing a spreadsheet program. But
> programmers should be familiar with computers, and most definitely
> should be familiar with 2's complement arithmetic.
> 
> Similarly, if you do much with floating point, you should be familiar
> with "What Every Computer Scientist Should Know About Floating-Point
> Arithmetic"
> 
> http://docs.sun.com/source/806-3568/ncg_goldberg.html

It's a valid viewpoint, but it is a 'should'. I believe many programmers 
have only passing familiarity if at all with the semantics of unsigned types 
and floating point operations. At least when coding, they don't have these 
semantics in mind. Why do you think Java doesn't have unsigned types? 

As the language designer you can say that your target users must have this 
knowledge, that's fine. Paraphrasing Alexandrescu: this is one of those 
fundamental coordinates that put D on the landscape of programming 
languages. I'm quite sure though that when you go look at the empirical side 
of the story, 'should' does not equate with 'is'.

However D does seem to target C#/Java and even python programmers. It is 
often suggested D's 'system programming' features are not actually *needed* 
and it offers enough high-level and safe features for programmers not 
comfortable with C / C++ to program effectively. This reasoning does not 
hold for unsigned integers and floating point vagaries.
February 16, 2010
Re: disabling unary "-" for unsigned types
Steven Schveighoffer wrote:
> On Mon, 15 Feb 2010 17:21:09 -0500, Walter Bright 
> <newshound1@digitalmars.com> wrote:
> 
>> Steven Schveighoffer wrote:
>>> are there any good cases besides this that Walter has?  And even if 
>>> there are, we are not talking about silently mis-interpreting it.  
>>> There is precedent for making valid C code an error because it is 
>>> error prone.
>>
>>
>> Here's where I'm coming from with this. The problem is that CPU 
>> integers are 2's complement and a fixed number of bits. We'd like to 
>> pretend they work just like whole numbers we learned about in 2nd 
>> grade arithmetic. But they don't, and we can't fix it so they do. I 
>> think it's ultimately fruitless to try and make them behave other than 
>> what they are: 2's complement fixed arrays of bits.
>>
>> So, we wind up with oddities like overflow, wrap-around, 
>> -int.min==int.min. Heck, we *rely* on these oddities (subtraction 
>> depends on wrap-around). Sometimes, we pretend these bit values are 
>> signed, sometimes unsigned, and we mix together those notions in the 
>> same expression.
> 
> One further thing I'll say on this:
> 
> signed computer math makes a lot of sense to people because the limits 
> are so large.  For instance, -2 billion to 2 billion.  It seems logical 
> that a computer can't just keep coming up with new bits to represent 
> numbers, but it seems so far off that an integer will wrap at 2 
> billion.  But unsigned math has a much more familiar boundary -- zero.  
> Numbers are far more likely to be near zero than they are near 2 billion 
> or -2 billion.  Applying a negation operator to an unsigned value almost 
> *guarantees* wrapping past that boundary.  99% of the time, when I apply 
> a negative sign to a number, I want the negative equivalent of that 
> number.  I don't want some large bizarre value that has no relation to 
> that number, despite what the computer thinks is sane.  I'd look at 
> applying a negation operator to an unsigned int with as much scrutiny as 
> I'd look at multiplying an integer by 1_000_000_000.  It's almost 
> guaranteed to go out of bounds, why are you doing it?
> 
> Bringing up -int.min == int.min is exactly my point.  For integers, 
> there is one value that the negation operator doesn't work as expected.  
> For unsigned integers, there is only one number that *does* work as 
> expected -- zero.  All others either don't work as expected, or rely on 
> the computer behaving strangely (if it is indeed expected).  To make 
> such rare purposeful uses more explicit does not lower the quality of 
> code or the ease of use.

Well said.

-Lars
February 16, 2010
Re: disabling unary "-" for unsigned types
Lutger wrote:
> It's a valid viewpoint, but it is a 'should'. I believe many programmers 
> have only passing familiarity if at all with the semantics of unsigned types 
> and floating point operations. At least when coding, they don't have these 
> semantics in mind. Why do you think Java doesn't have unsigned types? 

Naive programmers have trouble with Java floating point as well:

    http://www.eecs.berkeley.edu/~wkahan/JAVAhurt.pdf

There's just no getting around it. Should Java just remove floating 
point types as well?

Heck, I knew a degree'd mechanical engineer who could not understand why 
his calculator kept giving him answers off by a factor of 2 (he refused 
to understand roundoff error, no matter how many times I tried to 
explain it to him - he believed that calculators had mathematically 
perfect arithmetic). We could ban calculators, but misuse of slide rules 
is far worse.


> However D does seem to target C#/Java and even python programmers. It is 
> often suggested D's 'system programming' features are not actually *needed* 
> and it offers enough high-level and safe features for programmers not 
> comfortable with C / C++ to program effectively. This reasoning does not 
> hold for unsigned integers and floating point vagaries. 

Pointers are far more troublesome than negating an unsigned.

In my experience with beginning programming courses, the very first 
thing they explained was 2's complement arithmetic. I do not think it 
unreasonable at all that someone using a powerful systems programming 
language ought to understand it.
February 16, 2010
Re: disabling unary "-" for unsigned types
Walter Bright wrote:
> Lutger wrote:
>> It's a valid viewpoint, but it is a 'should'. I believe many 
>> programmers have only passing familiarity if at all with the semantics 
>> of unsigned types and floating point operations. At least when coding, 
>> they don't have these semantics in mind. Why do you think Java doesn't 
>> have unsigned types? 
> 
> Naive programmers have trouble with Java floating point as well:
> 
>     http://www.eecs.berkeley.edu/~wkahan/JAVAhurt.pdf
> 
> There's just no getting around it. Should Java just remove floating 
> point types as well?
> 
> Heck, I knew a degree'd mechanical engineer who could not understand why 
> his calculator kept giving him answers off by a factor of 2 (he refused 
> to understand roundoff error, no matter how many times I tried to 
> explain it to him - he believed that calculators had mathematically 
> perfect arithmetic).

How could he refuse? One of my favorite games with calculators was to 
successively extract square root of 2 until I got 1. The better the 
calculator, the more steps it takes. That's kind of difficult to refuse 
to acknowledge :o).

Andrei
1 2 3 4 5 6 7 8
Top | Discussion index | About this forum | D home