10

For example, why long int has a literal modifier, but short int does not? I am referring to the following question on this site: C# compiler number literals

In general, C# seems to be a very well designed and consistent language. Probably there is a strong reason to provide literal modifiers for some types, but not for all. What is it?

Community
  • 1
  • 1
Arne Lund
  • 2,366
  • 3
  • 26
  • 39
  • 1
    Take a look at this question (and Eric Lippert's answer): http://stackoverflow.com/questions/1678591/why-are-number-suffixes-necessary – Jason Down Dec 29 '11 at 18:13

6 Answers6

46

Why long int has a literal modifier, but short int does not?

The question is "why does C# not have this feature?" The answer to that question is always the same. Features are unimplemented by default; C# does not have that feature because no one designed, implemented and shipped the feature to customers.

The absence of a feature does not need justification. Rather, all features must be justified by showing that their benefits outweigh their costs. As the person proposing the feature, the onus is on you to describe why you think the feature is valuable; the onus is not on me to explain why it is not.

Probably there is a strong reason to provide literal modifiers for some types, but not for all. What is it?

Now that is a more answerable question. Now the question is "what justifies the literal suffix on long, and why is that not also a justification for a similar literal suffix on short?"

Integers can be used for a variety of purposes. You can use them as arithmetic numbers. You can use them as collections of bit flags. You can use them as indices into arrays. And there are lots of more special-purpose usages. But I think it is fair to say that most of the time, integers are used as arithmetical numbers.

The vast majority of calculations performed in integers by normal programs involve numbers that are far, far smaller than the range of a 32 bit signed integer -- roughly +/- two billion. And lots of modern hardware is extremely efficient when dealing solely with 32 bit integers. It therefore makes sense to make the default representation of numbers to be signed 32 bit integers. C# is therefore designed to make calculations involving 32 bit signed integers look perfectly normal; when you say "x = x + 1" that "1" is understood to be a signed 32 bit integer, and odds are good that x is too, and the result of the sum is too.

What if the calculation is integral but does not fit into the range of a 32 bit integer? "long" 64 bit integers are a sensible next step up; they are also efficient on a lot of hardware and longs have a range that should satisfy the needs of pretty much anyone who isn't doing heavy-duty combinatorics that involve extremely large numbers. It therefore makes sense to have some way to specify clearly and concisely in source code that this literal here is to be treated as a long integer.

Interop scenarios, or scenarios in which integers are used as bit fields, often require the use of unsigned integers. Again, it makes sense to have a way to clearly and concisely specify that this literal is intended to be treated as an unsigned integer.

So, summing up, when you see "1", odds are good that the vast majority of the time the user intends it to be used as a 32 bit signed integer. The next most likely cases are that the user intends it to be a long integer or an unsigned int or unsigned long. Therefore there are concise suffixes for each of those cases.

Thus, the feature is justified.

Why is that not a justification for shorts?

Because first, in every context in which a short is legal, it is already legal to use an integer literal. "short x = 1;" is perfectly legal; the compiler realizes that the integer fits into a short and lets you use it.

Second, arithmetic is never done in shorts in C#. Arithmetic can be done in ints, uints, longs and ulongs, but arithmetic is never done in shorts. Shorts promote to int and the arithmetic is done in ints, because like I said before, the vast majority of arithmetic calculations fit into an int. The vast majority do not fit into a short. Short arithmetic is possibly slower on modern hardware which is optimized for ints, and short arithmetic does not take up any less space; it's going to be done in ints or longs on the chip.

You want a "long" suffix to tell the compiler "this arithmetic needs to be done in longs" but a "short" suffix doesn't tell the compiler "this arithmetic needs to be done in shorts" because that's simply not a feature of the C# language to begin with.

The reasons for providing a long suffix and an unsigned syntax do not apply to shorts. If you think there is a compelling benefit to the feature, state what the benefit is. Without a benefit to justify its costs, the feature will not be implemented in C#.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    consistency should be a strong enough justification, should it not? However, this inconsistency seems to be there for a reason: it warns me of the costs of conversion to int and back to short every time I need to do anything with my short. – Arne Lund Dec 29 '11 at 21:29
  • @Lund: There is hardly any cost associated with the conversion, unless using checked arithmetic. Arithmetic is done in CPU registers which are always at least 32 bits wide. The memory load and store instructions actaully do the conversions, and they may vary slightly in cycle count. However, the beter cache utilization frequently more than makes up for any loss, potentially making the overall performance using shorts better than using ints. – Kevin Cathcart Jan 05 '12 at 20:31
  • 4
    @KevinCathcart: Provided of course that the shorts are tightly packed. An array of shorts, for example, might result in fewer cache misses than an array of ints. But often I see people who declare *local variables* as short because they figure that doing so is "saving two bytes of memory", which is nonsense. – Eric Lippert Jan 05 '12 at 20:48
9

According to MSDN:

short x = 32767;

In the preceding declaration, the integer literal 32767 is implicitly converted from int to short. If the integer literal does not fit into a short storage location, a compilation error will occur.

So it is a compile time feature. short does not have a suffix because it would never be needed.

The related question probably is : Why do long, float and decimal do have suffixes?
And a short answer would be that i + 1 and i + 1L can produce different values and are therefore of different types.

But there exists no such thing as 'short arithmetic', short values are always converted to int when used in a calculation.

H H
  • 263,252
  • 30
  • 330
  • 514
4

As Eric points out in the comment, my answer below doesn't make sense. I think it's more correct to say that the inability to express a short literal in C# and the inability to express a short literal in IL share a common cause (the lack of a compelling reason for the feature.) VB.Net apparently has a short literal specifier, which is interesting (for backwards compatibility with VB syntax?) In any case, I've left the answer here as some of the information may be interesting, even if the reasoning is incorrect.


There is no short literal because there is not actually any way for a short literal to be loaded in IL, the underlying language used by the CLR. This is because all 'short' types (anything smaller than an int) are implicitly widened to an int when loaded onto the operation stack. Signed and unsigned are likewise a matter of operations and not actually 'stored' with the active number on the operation stack. The 'short' types only come into play when you want to store a number on the operation stack into a memory location, so there are IL operations to Convert to various 'short' types (though it actually still widens the number back to an int after the conversion; it just makes sure that the value will be suitable for storing into a field of the 'short' type.)

Long types have a literal specifier, on the other hand, due to the fact that they are treated differently on the operation stack. There is a separate Ldc_I8 instruction for loading constant long values. There are also Ldc_R4 (hence why you need 'f' for float) and Ldc_R8 (C# chooses this as it's default if you use a decimal number without a specifier.) Decimal is a special case, as it's not actually a primitive type in IL; it just has a built-in constant specifier 'm' in C# that compiles to a constructor call.

As for why there are no special short operations (and corresponding short literals), that's likely because most current CPU architectures do not operate with registers smaller than 32-bits, so there is no distinction at the CPU level worth exploiting. You could potentially save code size (in terms of bytes of IL) by allowing for 'short' load IL opcodes, but at the cost of additional complexity for the jitter; the code space saved is probably not worth it.

Dan Bryant
  • 27,329
  • 4
  • 56
  • 102
  • ("you could potentially save code size...") -- But there *are* "short" opcodes, for saving bytes of IL (meaning the CIL code is short, not necessarily that they concern the `short` data type). For example, one even exists for i4 (four-byte ints): `ldc.i4.s` takes a one-byte argument, and pushes that value onto the stack as an int32. From the spec: "There are special short encodings for the integers –128 through 127 (with especially short encodings for –1 through 8)." – phoog Dec 29 '11 at 18:54
  • 5
    This answer doesn't make any sense. The fundamental error is in the first sentence. If the reason why the feature is not in C# is because C# compiles to IL, then why is the feature in other languages that compile to IL? – Eric Lippert Dec 29 '11 at 20:09
2

Since a short can be implicitly converted to int, long, float, double, or decimal; there's no need for a literal modifier.

Consider:

void method(int a) {}
void method2()
{
    short a = 4;
    method(a); // no problems
}

You may notice that char and byte are also with literal modifiers, for possibly this same reason.

From    To
sbyte   short, int, long, float, double, or decimal
byte    short, ushort, int, uint, long, ulong, float, double, or decimal
short   int, long, float, double, or decimal
ushort  int, uint, long, ulong, float, double, or decimal
int     long, float, double, or decimal
uint    long, ulong, float, double, or decimal
long    float, double, or decimal
char    ushort, int, uint, long, ulong, float, double, or decimal
float   double
ulong   float, double, or decimal
Joe
  • 80,724
  • 18
  • 127
  • 145
  • 4
    Your method2 demonstrated `short` => `int` conversion, that's the other direction than in `short s = 1;` – H H Dec 29 '11 at 18:27
1

The time I have "worked in Short" was for values that are stored in a Database.

They are positive integer values that will rarely go over 10 to 20.(a byte or sbyte would be big enough, but I figured a little over kill would keep me from regretting my choice, if the code got reused in a slightly different way)

The field is used to let the user sort the records in a table. This table feeds a drop down or radio button list that is ordered by "time" (step one, step two, ...).

Being new to C# (and old enough to remember when counting bytes was important) I figured it would be a little more efficient. I don't do math on the values. I just Sort them (and swap them between records). The only math so far has been "MaxInUse"+1 (for new records), which is a special case "++MaxInUse". This is good, because the lack of a literal means "s = s+2" would have to be "s = (Int16)(s+2)".

Now that I see how annoying C# makes working with the other ints, I expect to join the modern world and waste bytes, JUST to make the compiler happy.

But, shouldn't "making the compiler happy" rank about #65 in our top 10 programming goals?

Is it EVER an advantage to have the compiler complain about adding the integer "2" to ANY of the INTEGER types? It should complain about "s=123456", but that's a different case.

If anyone does have to deal with math AND shorts, I suggest you make your own literals. (How many could you need?)

short s1= 1, s2 = 2, s123 = 123;

Then s = s + s2 is only a little annoying (and confusing for those who follow after you).

Greg Little
  • 3,360
  • 2
  • 19
  • 16
  • Got to thinking, I should test, instead of just blasting off a good idea. s = s + s2; Gives the same error as s=s+2. The C# compiler is so annoying about being strongly typed, a Short + a Short yields an Int. This may be why several people asserted that all math is done as Ints. Based on this test, I propose an answer to the original question. A short literal does not exist, because it would never be helpful. Even if you had one, you can't add 2 Shorts and put it into another Short. (This leads me back in a circle to ask WHY. But, that's for another day.) – Greg Little Feb 21 '14 at 22:54
1

If you declare a literal short and make it larger than Short.MaxValue a compiler error will occur, otherwise the literal will be a short.

Bas
  • 26,772
  • 8
  • 53
  • 86
  • 1
    A literal can be long, such as 1L. Apparently there is no such thing as a short literal. – Arne Lund Dec 29 '11 at 18:11
  • 1
    @BasB: This isn't quite correct: you can declare a variable or a constant that's `short`, but you have to initialize it with a non-short literal; the range checking is done, as you note, by the compiler. The C# spec (4.0) defines literals in section 2.4.4, and, of integer literals, it says that they "are used to write values of types `int`, `uint`, `long`, and `ulong`." – phoog Dec 29 '11 at 18:38