views:

328

answers:

5

It looks strange especially for C++ developers. In C++ we used to mark parameter as const in order to be sure that its state will not be changed in method. There are also other C++ specific reasons also like passing const ref in order to pass by ref and be sure that state will not be changed. But why we can't mark as const method parameters in C# ?

Why I can't declare my method like this :

    ....  
    static void TestMethod1(const MyClass val)
    {}
    ....
    static void TestMethod2(const int val)
    {}
    ....
+5  A: 

const means "compile-time constant" in C#, not "readonly but possibly mutable by other code" as in C++. A rough analog of C++ const in C# is readonly, but that one is only applicable to fields. Aside from that, there is no C++-like notion of const correctness in C# at all.

The rationale is hard to tell for sure, because there are a lot of potential reasons, but my guess would be desire to keep the language simple first and foremost, and uncertain advantages of implementing this second.

Pavel Minaev
So you think MS considers like 'noise' to have const parameters in methods.
Incognito
I'm not sure what "noise" is - I'd rather call it "high cost/benefit ratio". But, of course, you'll need someone from C# team to tell you for sure.
Pavel Minaev
A: 

C# doesn't have const correctness like C++, because VB.NET doesn't, and C# and VB.NET are evolving together. Maybe in C# 5.0 or 6.0... :)

alxx
-1 Pure conjecture, there are more obvious reasons. Also note that MS didn't decide to make the feature set of C# and VB.NET consistent until more recently.
Noldorin
@Noldorin But they share the same runtime, so he is actually right. He only phrased it wrong.
EricSchaefer
No, saying "C# doesn't because VB.NET doesn't" is simply conjecture.
Noldorin
Your sentence is logically wrong.
mathk
@EricSchaefer I disagree: as soon as the .Net platform is a Turing complete machine you can do "whatever you want".
mathk
This answer is not logical. By this logic, C# also does not have iterator blocks, because VB doesn't. Since C# plainly does have iterator blocks, the logic must be incorrect.
Eric Lippert
@mathk: Can you explain what Turing completeness has to do with the design of a type system?
Eric Lippert
http://www.infoworld.com/d/developer-world/microsoft-converging-programming-languages-831?source=fssrRead this, people. How long will you debate my "conjectures"...
alxx
@Eric Lippert It mean that if the .Net is a Turing Complete machine you can implement any kind of language Python Java C# smalltalk Scheme LISP... Thus saying that VB.Net does not so C# is not likely to have make no sense. Look at Clojure which is an Scheme like implementation under the JVM. (Clojure have lambda/closure, dynamic typing, whereas Java do not and there can still be interpret by the same VM)
mathk
@alxx this is a political reason not a technical issue. But I see your point you should have point it out.
mathk
+7  A: 

One of the reasons why there's no const correctness in C# is because it doesn't exist at the runtime level. Remember that C# 1.0 did not have any feature unless it was part of the runtime.

And several reasons why the CLR does not have a notion of const correctness are for example:

  1. It complicates the runtime; besides, the JVM didn't have it either, and the CLR basically started as a project to create a JVM-like runtime, not a C++-like runtime.
  2. If there is const correctness at the runtime level, there should be const correctness in the BCL, otherwise the feature is pretty much pointless as far as the .NET Framework is concerned.
  3. But if the BCL requires const correctness, every language on top of the CLR should support const correctness (VB, JavaScript, Python, Ruby, F#, etc.) That's not going to happen.

Const correctness is pretty much a language feature only present in C++. So it pretty much boils down to the same argumentation as to why the CLR does not require checked exceptions (which is a Java language-only feature).

Also, I don't think you can introduce such a fundamental type system feature in a managed environment without breaking backward compatibility. So don't count on const correctness ever entering the C# world.

Ruben
Are you sure that JVM doesn't have it. As I know it has it. You can try public static void TestMethod(final int val)in Java.
Incognito
Final is not really const. You can still change fields on the reference IIRC, just not the value/reference itself. (Which is passed by value anyway, so it's more a compiler trick to prevent you from changing the parameter value.)
Ruben
your 3rd bullet is only partlly true. having const parameters for BCL calls would not be a breaking change since they merely describe the contract more precisely. "This method will not change the state of the object" in contrast to "This method require you to pass a const value" which would be breaking
Rune FS
@Rune FS: What is the point then from a language point of view, if it is not enforced? If it's for documentation purposes, you can already indicate that with an XML doc comment.
Ruben
It is enforced _inside_ the method so it wouldn't be a breaking change to introduce it in the BCL.
Rune FS
@Rune FS: What you're describing is equivalent to Java's **final**, IIRC (readonly in C# for fields). In C++ it is not possible to call any method on a const variable/parameter unless they are marked as const. So introducing C++ const correctness on parameters makes the parameters completely unusable, as there are no const methods. (Unless you introduce those too, but then you'd get back to all languages needing to support const correctness).
Ruben
No im not describing final and you're not describing a Breaking change caused by const on parameters but simply stating that to introduce it in the BCL requires work and a lot of it which i've never disputer. I Stated that it could be done without breaking client code. Just as you can add const to an argument in c++ without worrying about changing all the calling sites
Rune FS
@Rune FS: That means you can only add const to parameters that receive arguments that are already immutable, and sealed (otherwise you could make e.g. ToString mutate stuff that it's not intended to change in a derived class, breaking const correctness), and then also add const to all their methods and properties (otherwise the existing methods would break). Also, the BCL can never allow const parameters of non-sealed classes. Or interfaces. Or delegates. Because they are already non-const. That would make it a very limited feature IMHO; just for primitives and some classes like string.
Ruben
+3  A: 

I believe there are two reasons C# is not const-correct.

The first is understandibility. Few C++ programmers understand const-correctness. The simple example of const int arg is cute, but I've also seen char * const * const arg - a constant pointer to constant pointers to non-constant characters. Const-correctness on pointers to functions is a whole new level of obfuscation.

The second is because class arguments are references passed by value. This means there's already two levels of constness to deal with, without an obviously clear syntax. A similar stumbling point is collections (and collections of collections, etc).

Const-correctness is an important part of the C++ type system. It could - in theory - be added to C# as something that is only checked at compile-time (it doesn't need to be added to the CLR, and wouldn't affect the BCL unless the notion of const member methods were included).

However, I believe this is unlikely: the second reason (syntax) would be quite difficult to solve, which would make the first reason (understandibility) even more of a problem.

Stephen Cleary
You're right that CLR doesn't really need to worry about this, as one can use `modopt` and `modreq` on metadata level to store that info (as C+/CLI already does - see `System.Runtime.CompilerServices.IsConst`); and this could be trivially extended to const methods as well.
Pavel Minaev
+5  A: 

In addition to the other good answers, I'll add yet another reason why to not put C-style constness into C#. You said:

we mark parameter as const in order to be sure that its state will not be changed in method.

If const actually did that, that would be great. Const doesn't do that. The const is a lie!

Const doesn't provide any guarantee that I can actually use. Suppose you have a method that takes a const thing. There are two code authors: the person writing the caller and the person writing the callee. The author of the callee has made the method take a const. What can the two authors assume is invariant about the object?

Nothing. The callee is free to cast away the const and mutate the object, so the caller has no guarantee that calling a method that takes a const actually will not mutate it. Similarly, the callee cannot assume that the contents of the object will not change throughout the action of the callee; the callee could call some mutating method on a non const alias of the const object, and now the so-called const object has changed.

C-style const provides no guarantee that the object will not change, and is therefore broken. Now, C already has a weak type system in which you can do a reinterpret cast of a double into an int if you really want to, so it should not be a surprise that it has a weak type system with respect to const as well. But C# was designed to have a good type system, a type system where when you say "this variable contains a string" that the variable actually contains a reference to a string (or null). We absolutely do not want to put a C-style "const" modifier into the type system because we don't want the type system to be a lie. We want the type system to be strong so that you can reason correctly about your code.

Const in C is a guideline; it basically means "you can trust me to not try to mutate this thing". That shouldn't be in the type system; the stuff in the type system should be a fact about the object that you can reason about, not a guideline to its usage.

Now, don't get me wrong; just because const in C is deeply broken doesn't mean that the whole concept is useless. What I would love to see is some actually correct and useful form of "const" annotation in C#, an annotation that both humans and compilers could use to help them understand the code, and that the runtime could use to do things like automatic paralellization and other advanced optimizations.

For example, imagine if you could "draw a box" around a hunk of code and say "I guarantee that this hunk of code performs no mutations to any field of this class" in a way that could be checked by the compiler. Or draw a box that says "this pure method mutates the internal state of the object but not in any way that is observable outside the box". Such an object could not be safely multi-threaded automatically but it could be automatically memoized. There are all kinds of interesting annotations we could put on code that would enable rich optimizations and deeper understanding. We can do way better than the weak C-style const annotation.

However, I emphasize that this is just speculation. We have no firm plans to put this sort of feature into any hypothetical future version of C#, if there even is one, which we have not announced one way or the other. It is something I would love to see, and something which the coming emphasis on multi-core computing might require, but none of this should be in any way construed to be a prediction or a guarantee of any particular feature or future direction for C#.

Now, if what you want is merely an annotation on the local variable that is a parameter that says "the value of this parameter doesn't change throughout the method", then, sure, that would be easily done. We could support "readonly" locals and parameters that would be initialized once, and a compile-time error to change in the method. The variable declared by the "using" statement is already such a local; we could add an optional annotation to all locals and parameters to make them act like "using" variables. It's never been a very high priority feature so it has never been implemented.

Eric Lippert
Thank you Eric. I really enjoy your answer.
Incognito
Good explanation, and while I don't have the knowledge to debate whether const-correctness should be in C#, I agree that some kind of read-only-annotation would be very useful, both on parameters and on methods. Also, our very nature as programmers make us much better at documenting our code through declarative statements than through written, imprecise text. Or at least that's me. :)
Staffan E
@eric: to achieve const correctness, why not just disallow casting on the variable?
Craig Johnston