6

Consider this static test class:

public static class Test
{
    public static ushort sum(ushort value1, ushort value2)
    {
        return value1 + value2
    }
}

This causes the following compile error, with value1 + value2 underlined in red:

Cannot implicitly convert type 'int' to 'ushort'. An explicit conversion exists (are you missing a cast)?

Why?

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
  • 1
    The compiler is asking you to be explicit about the fact that you're making a narrowing conversion, where data may be lost. If you pass in ushort.MaxValue and 1, what should happen? That's the question the compiler is reminding you to answer. – Dan Bryant Jul 21 '10 at 18:04
  • @Dan: What should happen is the `ushort` should automatically overflow, or throw an overflow exception if the `checked` keyword is being used. If you add two `int` values, you don't get the same compiler error, even though overflow is possible. – Robert Harvey Jul 21 '10 at 18:56
  • My take: overflow is something that occurs as a result of an operation, not an assignment. In particular, you can overflow in the middle of a complex computation even if the final result would be in the range. If an overflow occurs, the math has failed to operate as expected, but this does not occur when adding two ushorts on a 32-bit system. The math worked fine, but you now have to decide how to interpret the result. If you want it to overflow ushort, then you can cast it to a ushort explicitly. This could happen implicitly, but requiring an explicit cast is helpful. – Dan Bryant Jul 21 '10 at 19:38

4 Answers4

7

Like C and C++ before it, integers are implicitly widened when used with many operators. In this case, the result of adding two ushort values together is int.

Update:

More information: http://msdn.microsoft.com/en-us/library/aa691330(v=VS.71).aspx

I believe this was originally added in C/C++ because int was a native integer type (and yes, operations were faster on ints than on shorts on 32-bit architectures). I'm unsure of the full rationale for C#.

It does make you think about overflow/truncation considerations when you cast. Accidental overflow is more likely with the smaller integer types.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • So it's done that way because it's always been done that way? – Robert Harvey Jul 21 '10 at 17:45
  • Because the conversions have to exist anyway, it is easier to convert to a single type and apply the operators than to implement the operators separately for every type on top of the conversions that already exist. – murgatroid99 Jul 21 '10 at 17:47
  • 2
    That, and the machine implicitly does arithmetic as 'int'. Also, if there are a lot of implicit conversions, it becomes far more likely that the compiler will pick a conversion that you didn't really intend. (See PL/I, for example.) – Eric Brown Jul 21 '10 at 17:47
  • See updated answer. I believe Eric's comment about the virtual machine arithmetic is the most likely reason why this is still done today. – Stephen Cleary Jul 21 '10 at 17:54
  • 1
    @Robert: "Otherwise, both operands are converted to type `int`." That would apply to two `ushort` operands. – Powerlord Jul 21 '10 at 17:59
5

ushort

The following assignment statement will produce a compilation error, because the arithmetic expression on the right-hand side of the assignment operator evaluates to int by default.

ushort z = x + y;   // Error: conversion from int to ushort

To fix this problem, use a cast:

ushort z = (ushort)(x + y);   // OK: explicit conversion
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
2

The available addition operators in C# only contemplate int, uint, long and ulong data types so in that case you are implicitly casting two ushort instances to int, then performing the addition and then returning an int that cannot be implicitly cast to ushort.

From the C# 4.0 specification, section 7.8.4 Addition operator, you can check that only the the following integer addition operators are available:

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

The same section also states:

The operands are converted to the parameter types of the selected operator, and the type of the result is the return type of the operator.

Which explains why that expression results in an int.

João Angelo
  • 56,552
  • 12
  • 145
  • 147
1

It is because addition or subtraction of ushorts doesn't necessarily result in a ushort. For example, the result could be < 0, which is not a ushort. So you need to give the compiler the hint to not complain by type casting it. I believe this should work: return (ushort)(value1 + value2);

AlvinfromDiaspar
  • 6,611
  • 13
  • 75
  • 140