Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does C# issue the error "cannot implicitly convert int to ushort" against modulo arithmetic on ushorts?

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?

like image 780
Gregory Fenn Avatar asked Apr 11 '19 17:04

Gregory Fenn


People also ask

Why does the letter C exist?

The letter c was applied by French orthographists in the 12th century to represent the sound ts in English, and this sound developed into the simpler sibilant s.

What is '#' in C language?

'#' is called pre-processor directive and the word after '#' is called pre-processor command. Pre-processor is a program which performs before compilation. Each pre-processing directive must be on its own line.


2 Answers

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.

like image 37
adjan Avatar answered Oct 20 '22 00:10

adjan


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.
like image 156
Jonathon Chase Avatar answered Oct 20 '22 01:10

Jonathon Chase