2

I saw code that goes like this:

double d = GetDouble();
DoSomething(+d);
DoSomething(-d);

I know in it is potentially dangerous and not recommended in C++ to use the unary + just to emphasize that the value is positive. <EDIT>"just to emphasize that the value is positive" was a mental shortcut. I know it doesn't make a negative value positive.</EDIT>

The C# language reference doesn't say much about it:

The unary + operator returns the value of its operand.

There is a question on SO about this, but it is tagged with C, C++ and C#, and none of the answers clearly mentions C#.

michuu
  • 315
  • 4
  • 10
  • 1
    What do you mean by “safe”? It exists, it does what it does, it wouldn’t exist if it was somehow dangerous or not-to-be-used. Also it does not emphasize the value being positive, the value can be negative also. – Sami Kuhmonen Apr 06 '23 at 12:33
  • 4
    _"just to emphasize that the value is positive"_ - it doesn't do that: https://dotnetfiddle.net/tVbiaQ – Fildor Apr 06 '23 at 12:34
  • What are you trying to achieve? C# is a completely different programming language, albeit C like. – phuzi Apr 06 '23 at 12:34
  • As they would in a Mathematical formula, the operators act as "+1 * value" or "-1 * value". But that's regardless of whether the value is positive or negative. With + the sign does not change, with - the sign is flipped. (On the evaluated expression, not the value itself as shown in Peter's answer.) – Fildor Apr 06 '23 at 12:40
  • 1
    On all .NET number types the unary + is a no-op. You can however [overload this operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading) for your own types. – Olivier Jacot-Descombes Apr 06 '23 at 12:44
  • 2
    _"You can however overload this operator for your own types."_ - which would be surprizing to the average developer, though :( – Fildor Apr 06 '23 at 12:45
  • 1
    What do you mean by "safe"?" Are you asking if it has the same "potentially dangerous" effects as in C++? If so, what are the "potentially dangerous" effects of unary `+` in C++? Please clarify. – Sweeper Apr 06 '23 at 12:45
  • I'm asking about the potentially dangerous effects, not how it affects the value. In c++, arithmetic promotion is performed, which for example may affect which function overload is choosed. – michuu Apr 06 '23 at 12:47
  • Why not test it quick if you want to be sure? https://dotnetfiddle.net/aS89qy – Fildor Apr 06 '23 at 12:51
  • @Fildor I'm asking not only about changing the type. I want to know if it is considered a good and safe practise in general. – michuu Apr 06 '23 at 12:53
  • Practice for what? Indicating that the value is supposed to be positive? - Then no, it's not good for that. – Fildor Apr 06 '23 at 12:54
  • No for that, for indicating that value is not opposite, to put the emphasis on the absence of unary - (minus) – michuu Apr 06 '23 at 12:57
  • https://dotnetfiddle.net/R6V0OU - look at this. Even in the case of intentional errors with overloading of the unary plus operator and implicit type conversion, there will be no problem. Plus applied to `doube`, not to `MyDouble`. – Alexander Petrov Apr 06 '23 at 13:02

3 Answers3

7

As this answer of the question you linked says, unary + in C(++) does do something, and is not necessarily a no-op. This is true in C# too.

C# only has these unary + operators (See spec):

int operator +(int x);
uint operator +(uint x);
long operator +(long x);
ulong operator +(ulong x);
float operator +(float x);
double operator +(double x);
decimal operator +(decimal x);

So if x is a short, +x would be of type int, because the first operator is selected by overload resolution. As a result, something like this does not compile:

short x = 1;
short y = +x;

This also affects overload resolution, among other things. Just like the code presented in this answer, if you do:

public class C {
    public static void Foo(int x) {
        Console.WriteLine("int");
    }
    
    public static void Foo(short x) {
        Console.WriteLine("short");
    }
}

C.Foo(x) where x is a short will print short, but C.Foo(+x) will print int.

Does this situations like the above happens often enough that makes +x a "bad" or "unsafe" practice? That is for you to decide.

Of course, if x is of a custom struct/class type, then +x could do basically anything. Unary + is overloadable.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Does that type changing behavior make it not recommended in C# community? – michuu Apr 06 '23 at 13:10
  • 1
    @michuu No, as far as I'm aware. There isn't many situations like `C.Foo`, where there is an `int` overload and a `short` overload that does completely different things. Overloads are supposed to do *similar* things after all. So even if you call the "wrong" one, it should still behave the same (with just an extra useless conversion). When the type actually matters, it is better to give the methods different names. – Sweeper Apr 06 '23 at 13:13
  • Ok, thank you for the accurate answer! – michuu Apr 06 '23 at 13:18
1

+ and - will not change the original double value if that's what you mean by safe.

double d = 7d;
Console.WriteLine(d);  //7
Console.WriteLine(+d); //7
Console.WriteLine(-d); //-7
Console.WriteLine(d);  //7

//OR
d = -7d;
Console.WriteLine(d);  //-7
Console.WriteLine(+d); //-7
Console.WriteLine(-d); //7
Console.WriteLine(d);  //-7
Peter Csala
  • 17,736
  • 16
  • 35
  • 75
0

The other answers have provided a great explanation of what will go on with use of +.

Just wanted to flag that just like in C/C++ there also is the integral numeric types all have unsigned versions. Of course, both share the same concerns of wrapping around when bad operations are done with them

The following code snippet is just a joke, don't kill me, but here is an extension method to check if a numeric type is positive without risk of altering the original's value or typing

public static class NumericExtensions<T> where T : struct
{
    public static bool IsPositive(this T num) =>
        num switch  
        {  
            num is uint _ => true,
            num is int i => i > 0,
            num is ulong _ => true,
            num is long l => l > 0,
            num is double d => d > 0,
            num is float f => f > 0,
            num is decimal m => m > 0m
            //... add remaining numeric types
            _ => false //or throw exception
        };
}
Narish
  • 607
  • 4
  • 18