views:

450

answers:

7

In C#, the following type-inference works:

var s = "abcd";

But why can't the type be inferred when the variable is a constant?

The following throws a compile-time exception:

const var s = "abcd"; // <= Compile time error: 
                      //    Implicitly-typed local variables cannot be constant
+1  A: 

IMO var main purpose is to allow anonymous types (type is unknown, with var you can declare a variable to store it). The more common usage now is to write less code ;). As they explain here if you know the type and the value (which won't change) just write the type.

Beku
That doesn't explain why, you are merely repeating the question.
Jonathan Allen
You answer also doesn't explain why. This is an overuse of var which was created mainly for anonymous types.
Beku
Beku, that's not the point though. I'm merely asking because I'm curious about the decision of the Language designers.
Andreas Grech
+4  A: 

The short answer is because the language designers (Microsoft) say so.

From MSDN:

Compiler Error CS0822

Error Message: Implicitly typed locals cannot be const

Implicitly typed local variables are only necessary for storing anonymous types. In all other cases they are just a convenience. If the value of the variable never changes, just give it an explicit type. Attempting to use the readonly modifier with an implicitly typed local will generate CS0106.

To correct this error

If you require the variable to be constant or readonly, give it an explicit type.

Mark Byers
Yes I read that, but I was actually hoping someone like Eric Lippert would give a more technical explanation.
Andreas Grech
I think you have to say his name three times.
Mark Byers
And click your heels too?
Oded
ah looks like you beat me to it - I think this is enough of an explanation - 'since there's no reason to do what you're doing, what you're doing is wrong, and it's the job of the compiler to stop you from doing things like that :p'
Bobby
So then, following your argument, why doesn't the compiler stop me when I do: `var s = "abc";` ?
Andreas Grech
It's their argument too, "If the value of the variable never changes, just give it an explicit type.", see below.
Bobby
A: 

Interesting. I don't know if it is just a limitation of the C# compiler or if it a fundemental limitaion of the language itself.

To explain what I mean, consider VB.

In VB 9 you also couldn't infer constants, but this was just a limitation of the compiler. In VB 10 they were able to add constant type inference without making any significant changes the to language.

Jonathan Allen
+1  A: 

In this case it is obvious that you know the reference type will be constant, and of a fairly primitive type (consts can only be value types, or strings, etc..), so you should declare that type, rather than use implicit typing.

In other words, because the type is obviously constant and known, there's absolutely no reason to use var.

Implicitly typed local variables are only necessary for storing anonymous types. In all other cases they are just a convenience. If the value of the variable never changes, just give it an explicit type. Attempting to use the readonly modifier with an implicitly typed local will generate CS0106.

http://msdn.microsoft.com/en-us/library/bb310881.aspx

Compiler Error CS0822

To correct this error If you require the variable to be constant or readonly, give it an explicit type.

Bobby
But with `var s = "abc";`, the type is also know but there is no compiler error because the type is inferred. So your answer doesn't really answer my question.
Andreas Grech
I see your point, but that's not const -- if they prevented var s = "abc", then obviously none of the implicit typing would be possible.A const var = would clear never change, so it's clearly not what they wanted it to be used for, so be explicit--that's what the doc says.Implicit typing was added to make certain scenarios easier--namely linq. The language designers wanted to prevent dev's from writing bad code (eg const var) while making verbose types like IEnumerable<Foo<Bar>> = ... easier to deal with.In the end I don't think this is a limitation of the CLR, though.
Bobby
+13  A: 

First off, if there's something you want brought to my attention, you can always use the "Contact" link on my blog.

Second, I have only one thing to add to the other answers: "constant" and "variable" are opposites. "const var" gives me the shudders to type. A constant is a value that never changes and has no storage location; a variable is a storage location whose contents change. They're completely different, so don't attempt to combine them. The "var" syntax was chosen to call out "this is a variable", and we're sticking with it.

Eric Lippert
But is there a specific reason on why the designers chose not to implement type-inference for constants yet allow the use of `var` as syntactic sugar for known types (like `var s = "abc";`) ?
Andreas Grech
@Andreas, There are two main uses for impl typed locals: anonymous types, and elimination of redundancy. It is a pain to type Dictionary<string, List<decimal>> priceTable = new Dictionary<string, List<decimal>>(); -- the "var" eliminates the completely unnecessary verbose type declaration. Your example is an example of the latter, though I personally would frown upon var s = "abc"; or var i = 123; or, worst of all, var m = M();
Eric Lippert
If I have an equation in math and it contains a "variable" this variable often really is a constant. For example in "2x = 6" x is and always will be the value 3. Some people get shuddered by something like "x = x + 1", which is an insolvable equation, yet common in many programming languages including C#.
helium
@helium, the problem there is that programming languages abuse the = operator to mean "assign this value to this storage location", instead of using it to mean either "evaluate the truth or falsity of this equality", or "declare the equivalence of these two entities". I personally would rather that the = operator have been something like <-- in C/C++/C#/etc, but for historical reasons, we're stuck with = to mean assignment.
Eric Lippert
@Eric: I wonder if this is also related to your post "Why no var on fields?" - const is not a variable, but I wonder if the compiler handles const and fields similar? http://blogs.msdn.com/ericlippert/archive/2009/01/26/why-no-var-on-fields.aspx
Michael Stum
@Michael: the situations are not exactly the same but they are similar. I noted that we would have to worry about cyclic definitions in analysis of "var" fields. Today we have to worry about cycles in analysis of constants. If you say const int x = y + 10;, then the definition of const int y had better not depend on x.
Eric Lippert
+6  A: 

This is just a guess, but I think that the reason might have to do with the fact that const values are put in metadata (which has subtle consequences all it's own) when compiled. I wonder if maybe the compiler has some issues figuring out how to transform a var to metadata.

In Richter's CLR VIA C# (page 177),

Defining a constant causes creation of metadata. When code refers to a constant symbol, compilers look up that symbol in the metadata of the assembly that defines that constant, extract the constant's value, and embed the value in the emitted IL code.

He goes on to note that this means that you can't get the reference to memory of a constant for this reason. To make this a bit more explicit, in psuedo C# if assembly A defines a const:

//Assembly A, Class Widget defines this:
public static const System.Decimal Pi = 3.14

then you have a consumer of A:

//somewhere in the Program.exe assembly
decimal myCircleCurcum = 2 * Widget.pi

the resultant compiled IL of program.exe would do something like this pseudocode:

// pseudo-IL just to illustrate what would happen to the const
myCircleCurcum = 2*3.14

note that the consuming assembly has no idea that the decimal 3.14 had any relationship to Assembly A at all--it is to program.exe a literal value. This, to me, is a reasonable way for the C# compiler to act--after all, Assembly A declared explicitly that pi is a constant (meaning that the value is once and for all pi=3.14). But, I'd venture to guess, that 99% of C# developers do not understand the ramifications of this & might change pi to be 3.1415 on a whim.

Constants have a really poor cross-assembly version story (again, this comes from Richter) because a consumer of assembly A with a constant in it will not see a change if assembly A's constant changes (i.e. it was recompiled). This can cause really hard to figure out bugs by consumer of assembly A. . . so much so that I ban my team from using constants. Their slight perf gain is not worth the subtle bugs they can cause.

You can really only ever use a constant if you know that the value will never, ever change -- and even with something set as a const such as pi, you can't say for sure that you won't want your percision to change in the future.

if assembly A defines:

decimal const pi = 3.14

then you build it and then other assemblies consume it, if you then change assembly A:

decimal const pi = 3.1415

and rebuild assembly A, the consumer of assembly A will still have the old value 3.14! why? because the original 3.14 was defined as a constant which means that the consumers of assembly A have been told that the value won't change--so they can bake that value of pi into their own metadata (if you rebuild consumer of assembly A it will then get the new value of pi in it's metadata). Again, I don't see this as a problem with the way CSC handles constants--it's just that developers probably don't expect that a constant can't be changed safely under some circumstances, where it can be changed safely in others. Safe: no consumers will ever have reference by .dll only (i.e. they will always build from source EVERY TIME), unsafe: consumers don't have a clue about when source code of your assembly with the const defined it it changes. It probably should be made much more clear in .NET documentation that constant means you can't change the value in the sourcecode

For that reason, I'd strongly suggest not using constants and instead just making the widget readonly. How many values can you really say for certain are truly going to be const for ever and always?

The only real reason to use const over readonly in my mind is if something might have performance implications... but if you are running into that, I'd wonder if C# is really the correct language for your problem. In short, to me, it is alomst never a good idea to use constants. There are very few times where the tiny perf improvement is worth the potential problems.

Kevin Won
+1 very interesting answer and thanks for the reference.
Andreas Grech
A: 

I agree with Eric that this is ugly as sin:

const var s = "abcd"

But why not simply this?

const s = "abcd"

Seems like a reasonable syntax to me.

Keith Brown - Pluralsight