6

In another thread, someone asked about why adding two ushort values raised errors in C#. e.g.

ushort x = 4;
ushort y = 23;
ushort z = x+y;  // ERROR cannot implicitly convert int to ushort 

On that thread, people argued that the plus + operater takes two ints by default, and this is a language feature to help avoid arithmetic overflows. But I get the same kind of error in the following function:

public RGB(ushort red, ushort green, ushort blue)
{
    // this class RGB has three ushort fields: r, g, and b
    r = red % ((ushort)256);
    g = green % ((ushort)256);
    b = blue % ((ushort)256);
}

where the compiler errors and says "Cannot implicitly convert type 'int' to 'ushort'. An explicit conversion exists...". But here the argument that the modulo % operator is guarding against overflow doesn't make any sense at all: if x and y are ushort values, then x%y < max(x,y), so there is no risk of overflowing into ints. So why am I getting this error?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Gregory Fenn
  • 460
  • 2
  • 13

2 Answers2

7

The % operator that's being used, even with shorts or ushorts, has a signature of int %(int a, int b). So your shorts are being lifted up into integers, and your result is an integer you are attempting to assign to a ushort, which is a lossy cast so you are required to be explicit.

Consider this:

ushort x = 5;
ushort y = 6;
var res = x % y;
Console.WriteLine(res.GetType()); // System.Int32
ushort z = res; // cast error, explicit conversion exists
ushort zz = (ushort)res; // Fine, we cast down.
Jonathon Chase
  • 9,396
  • 21
  • 39
  • Oh sure, I figured that the signature was elevating it, but I don't understand *why* is has that signature. Why not overload and have several signatures like `ushort %(ushort a, ushort b)` , `int %(int a, int b)` , `long %(long a, long b)` , `ulong %(ulong a, ulong b)` ? – Gregory Fenn Apr 11 '19 at 18:03
  • 4
    @GregoryFenn: As I noted in another comment, language designers are not required to give reasons why they did not do something. Hardly anyone does arithmetic on ushorts; they pretty much exist only for compatibility with unmanaged code. The responsibility for justifying why a feature ought to exist is on the person who wants the feature; I don't have to give you a reason why I *didn't* do something you wanted; you have to give me a reason why I should! – Eric Lippert Apr 11 '19 at 18:16
  • Well the reason was stated in my OP, perhaps a little between the lines: but ok. You SHOULD implement the feature that `ushort %(ushort a, ushort b)` is a valid signature because it is mathematically IMPOSSIBLE to overflow a ushort into an int via modulo. – Gregory Fenn Apr 12 '19 at 12:44
  • @GregoryFenn The compiler is open source, you could look into designing this. I'm not sure preventing overflow is why operators for those types wasn't implemented, obviously the `int +(int a, int b)` operator does nothing to prevent overflow when adding two large integers together. – Jonathon Chase Apr 12 '19 at 23:19
1

It's because the % operator is not defined for integer types smaller than int. The C# spec lists all overloads defined for the modulo operator on integer types:

int operator %(int x, int y);
uint operator %(uint x, uint y);
long operator %(long x, long y);
ulong operator %(ulong x, ulong y);

https://github.com/dotnet/csharplang/blob/master/spec/expressions.md#remainder-operator

Using %on ushorts then defaults to the first overload from the list above, which returns an int that can't be cast to ushort implicitly.


If you ask why it's not defined, you probably would have to ask the creators of the C# specification.

adjan
  • 13,371
  • 2
  • 31
  • 48
  • 2
    I'd rather you didn't ask us "why not" questions; language designers are not required to give reasons why they did not do something! Rather, if there is a feature that you think is missing, you need to provide a justification of why it should exist. – Eric Lippert Apr 11 '19 at 18:14
  • I mean, I did use the word 'why' several times. If you didn't what to answer that, that's ok but my post already recognized that % was an invalid operator returning a ushort (except by extra casting), I was asking what the logic of this is. Like I said, in the other thread people argued it was to avoid overflow, and this was the accepted answer, but if they are going to be consistent then that wouldn't apply here. No one said that asking why " `ushort +(ushort, ushort)` is invalid" was an invalid question, so by the same token no one should have the right to say the same of mine. – Gregory Fenn Apr 12 '19 at 12:48