TIL C# has a unary Plus operator. Tracking this typo down took some time...

TIL C# has a unary Plus operator. Tracking this typo down took some time...

Posted Mar 6, 2020, 1:32 AM UTC

40760
AyrA_ch•
106
TASagentOP•

I don't know what's more amusing: the existence of the unary plus, or the note on the documentation you linked that "The ulong type doesn't support the unary - operator."

But we can all agree it's a good thing the ulong type supports unary plus.

81
Akitown•

I mean if you had var a = - ulong.MaxValue; what would the type of a be?

15
richarmeleon•

A floating point or decimal would be able to hold it but that would not be a normal use of a giant integer.

7
TASagentOP•

The exact code you wrote gives:

Operator '-' cannot be applied to operand of type 'ulong'

But substituting in the actual value of ulong.MaxValue there we still get:

Operator '-' cannot be applied to operand of type 'ulong'

Making it positive and adding 1 gives a different error:

Integral constant too large

The same error is given if you make it negative.

It seems that C# will never switch an integral type to a floating point, even if it must to represent the number, and I think that's a very good thing.

The question stems directly from one of the several reasons I hate var and will only use it for catching some tuples and some wordy iterators.

5
Akitown•

Thanks for the thorough answer! I was asking in a more theoretical kind of way tho, since you emphasized the ulong not supporting unary - operator part of the docs, because if you think about it there has to be a "biggest" integral numeric type, otherwise you would end up with types like long long long... going on forever (although I would very much like to see that).

1
JuhaJGam3R•

error CS0023 probably. or System.Numerics.BigInteger if you absolutely need to use -ulong.MaxValue

3
steVeRoll•

The unary + operator returns the value of its operand. 

You know what else returns the value of its operand? The operand!!!

12
supersharp•

I guess it's like writing +x (positive x) in regular math. Pointless, but still has meaning.

4
lxpnh98_2•

WHY?!?!?

6
blenderfreaky•

Maybe for formatting:

Foo(+a);
Foo(-a);

Is nice and aligned

14
otw•

Unary plus "does nothing"

I am not super familiar with C# but couldn't this be used to create a new value with a different type?

1
TASagentOP•

C# does support operator overloading. With Binary operators, like the + in "A + B", you can overload the operator for different input types, and give the different combinations different output types. With Unary operators, you can only have one overload (unsurprising), but it is allowed to change the object type.

But to actually do so would (almost) always be a terrible design decision. It can be done, but it almost certainly shouldn't.

2

That's not true actually. It casts the operand to a 32 bit integer. Ex. `byte a = 100; var b = +a;` b will be System.Int32.

1
AyrA_ch•

byte a = 100; var b = +a; b will be System.Int32.

This has nothing to do with the unary plus but with the fact that mathematical and binary operators aren't defined for the byte type.

It will also be that if you do this:

byte a = 1;
var b = a * a;
var c = a + 0;
var d = a - 0;
var e = (byte)a + (byte)0;
var f = ~a;

b,c,d,e,f will all be integers. You have to be careful when working with bytes in C#. Especially when you serialize them into a binary format, it's very easy to accidentally cast to int.

This might be one of the reason why MS doesn't recommends that you use var for primitives.

1

Yes but that implicitly implies it has a usage. "It does nothing" means the casting shouldn't be done either but it happens.

1
AyrA_ch•

It's not the unary plus that casts but the engine. Numbers in C# can be implicitly cast to other types provided they fit. Because there's no operator defined for the byte type, the engine converts it to an integer. By the time the number is given to the unary operator, it has already been converted to a 32 bit integer. The unary operator never gets a byte value. And therefore the documentation that "The unary + operator returns the value of its operand." is still valid.

What you describe as an conversion in the unary operator is merely a side effect observed by implicit numeric conversion.

If you don't like this, you can open an issue on Github and ask them to add an overload to the unary operator to support the byte type but I doubt they add it because it would make unary plus different from all other operators in regards to how a byte type is handled

2
TASagentOP•

Does anyone know of any case where the unary Plus isn't just implemented as identity?

I realize now: The true existential horror would be overloading the unary plus to do something else, because "calling functions is so ugly".

61
uninformed_•

In C++ the unary plus converts a lambda into a function pointer. Madness.

41
Nall-ohki•

Not exactly. A lambda is defined to be convertible to a function pointer iff it's a stateless lambda. Using the the + operator coerces it to a pointer as you're now doing math on a pointer.

This wasn't an expected effect, but works using type coersion... as c/c++ does

40
nana_3•

“This wasn’t an expected effect” = summary of all my c++ experiences

8
overkill•

But after 3 hours of research I can understand why the feature is there, and why I will never in a bajillion years need to use it until next week.

3
dragozir•

The best part about this is that stateful lambdas can be converted to function pointers by using a static function variable inside a template function, since all static lambdas can converted to a function pointer. Of course, you can misuse or mess this up pretty easy, but calling it with only prvalue lambdas will work everytime since the variable is only initialized once (you can get around that but the compiler has decidedly more work to do in regards to optimization).

1
HildartheDorf•

Not sure about C# but in C +foo where foo is smaller than an int will return an int.

Also let's you write vec3(+1,-1,+1) and it look less weird.

17
TASagentOP•

In C# the math operations seem to be defined starting for the 32-bit integer (int). Doing math on a byte or a short uses the implicit cast up to int for the arguments and outputs an int. This applies to both arithmetic operators and bitwise operations. I am glad that the Pre/Post Increment/Decrement operators (++ and --) don't do this, nor do the in-place operations (+=, -=, etc). Upon checking, the same is true of the Unary Plus.

byte a = 0;
byte c = 0;

////Compile error
//byte additionError = a + b;

//Valid
byte additionFixed = (byte)(a + b);

//additionTest is an int
var additionTest = a + b;

//inplaceTest is a byte
var inplaceTest = (a += c);

//Valid
byte b = ++a;

//unaryTest is an int
var unaryTest = +a;
2
MadP4ul•

In javascript it converts strings to numbers. You could do something like that. But overloading the cast would be better obviously. I think your problem would be easily fixed with autoformat btw. That would have moves the =+ apart.

13
great_site_not•

in JavaScript it converts anything to a number.

6
EkskiuTwentyTwo•

You can use this to make fake ternaries:

variable = [thingA,thingB][+(condition)];
2
great_site_not•

Unfortunately, that won't work for most conditions that aren't 1, 0, "1", "0", or a boolean. To make it work in the general case, you'd have to first coerce to a boolean like so:

variable = [thingA, thingB][+!!(condition)]

2
[deleted]•

[deleted]

1
TASagentOP•

I think your problem would be easily fixed with autoformat btw.

Yeah, I regularly hit Ctrl+K, Ctrl+D (Format Document). It does become much more obvious on format. I just hadn't done so between rewriting this particular function, testing it, and getting a strange result. Once I tracked it down, I definitely face-palmed.

1
[deleted]•

[deleted]

1
barburger•

This is a fine and probably common mistake to make, the horror is that whatever ide you are using is ok with it. For example resharper/rider would put a yellow highlight on the line saying space after unary plus is probably a bug.

24
Chaike•

Great, now I'm paranoid about every += I've written.

18
otw•

I'm confused what'd the issue?

16
HemnesMirrorball•

I think =+ instead of +=

40
tsvk•

Yes, and the =+ gets parsed as an assignment with a plus sign preceding the value to be assigned.

18
otw•

Oh got it I actually saw that and for some reason assumed it was an intentional coercion and something else was breaking with it lol I'm dumb way overcomplicated this in my head

3
arbenowskee•

Wow, I would've totally missed this one. A nasty typo. Does static code analysis catch these kinds of things?

9
navatwo•

A style linter would! It would tell you to put a space after the = between the + and remove the space after the +.

Would showcase the bug almost immediately!

One of several reasons I love stylecop being on for all of our projects with TreatWarningsAsErrors.

16
blenderfreaky•

Just let your ide format your code every know and then, makes the issues more obvious

Ctrl+K Ctrl+D

2
noop_noob•

I once had to write "x = -x;" in some code for a programming competition. I decided to write it as "x =- x;" cuz I found it funny.

4
blenderfreaky•

Do you also use the goes to operator?

int i = 10;

while (i --> 0) { Foo(i); }
7
zigs•

The real horror is always in the comments

5
noop_noob•

No lol.

2
[deleted]•

[deleted]

2
joonsson•

If I'm not mistaken what it says here is actually A = +B × C which I think should do nothing buy I am no C# expert. A += B × C which I think is what it should say is a shorter version of A = A + B × C however.

13
TASagentOP•

If you consider how x=-y; and x = -y; and x = - y; are all valid and mean the same thing, it's not hard to image why x =- y would be valid and mean the same thing as well. Indeed, support for the first statement means that the compiler can't require spaces between the operators in order to make digraphs special (nor should it).

3
DurianExecutioner•

Awesome, another job security measure right there.

2
joolzg67•

Maybe a new checker for static analysis check?

What did your static anaylsis tool say about this?

2
jmack2424•

Most languages have an order of operations issue with unary operators. Sometimes all the difference is using 2 variables in the sequence instead of one.

1
Debbus72•

Just out of interest, if you would format the document would it move the plus?

1
you0are0rank•

This seems like hours of fun

1
uninformed_•

,yuyuyuyuyjh

-11