110

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

Why can't I declare my method like the following?

    ....
    static void TestMethod1(const MyClass val)
    {}
    ....
    static void TestMethod2(const int val)
    {}
    ....
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Incognito
  • 16,567
  • 9
  • 52
  • 74
  • It was always just a safety-catch feature in C++, and never truly integral to the language as I saw it. C# devs didn't think it added much value evidently. – Noldorin Jul 16 '10 at 08:13
  • 3
    A bigger discussion at this question: "Const-correctness in c#": http://stackoverflow.com/questions/114149/const-correctness-in-c – tenpn Jul 16 '10 at 09:52
  • There is for value types [out/ref], but not reference types. It's a interesting question. – kenny Jul 16 '10 at 10:03
  • @kenny Sorry what you mean "there is for value types" ? You can't have const parameters no matter for value or reference types – Incognito Jul 16 '10 at 10:30
  • 4
    How could this question have both the C# and language-agnostic tags? – CJ7 Aug 08 '10 at 10:13
  • 1
    Immutable data and functions without side effects are easier to reason about. You might enjoy F# https://fsharpforfunandprofit.com/posts/is-your-language-unreasonable/ – Colonel Panic Mar 30 '19 at 19:40
  • Related post - [Const function parameter in C#](https://stackoverflow.com/q/10981888/465053) – RBT Jan 13 '22 at 06:20

5 Answers5

57

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
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 41
    Sorry, but I find this argument very weak, the fact that a developer can say a lie cannot be prevented in any language. void foo(const A& a) that modifies the object a is not different from int countApples(Basket b) that return the number of pears. It is just a bug, a bug that compile in any language. – Alessandro Teruzzi Sep 25 '15 at 14:41
  • 67
    _“The callee is free to cast away the const …”_ uhhhhh… (°_°) This is a pretty shallow argument you're making here.  The callee is also free to just start writing random memory locations with `0xDEADBEEF`.  But both would be ***very bad*** programming, and caught early and poignantly by any modern compiler.  _In the future when writing answers, please don't confuse what's technically possible by using a language's backdoors with what's feasible in actual real-world code.  Skewed information like this confuses less experienced readers, and degrades the quality of info on SO._ – Slipp D. Thompson Nov 04 '15 at 06:51
  • 8
    _“Const in C is a guideline;”_ Citing a source for some of the things you're saying would really help your case here.  In my education and industry experience the quoted statement is hogwash— const in C is as much of mandatory built-in feature as the type system itself— both have back-doors to cheat them when necessary (like really everything in C) but are expected to be used by the book in 99.99% of code. – Slipp D. Thompson Nov 04 '15 at 07:01
  • 6
    @SlippD.Thompson: First, I note that a feature which provides "a back door to cheat when necessary" that developers are expected to not use is precisely what I am talking about; const in C does not actually provide the guarantee that I would want in the language. Second, I object to your ad hominem slurs. Third, the question is a "why not?" question that inherently calls for an opinion -- an opinion that is in my case informed by my long association with the C# design committee. Finally, I encourage you to write a better answer, or write a blog post or some such thing, if you don't like mine. – Eric Lippert Nov 04 '15 at 14:35
  • 4
    Const in C++ is an effective and purposely intrusive guarantee of intention. Your example of the lying programmer is a bit far fetched. Sure it could be done better. However you have written some very good posts in the past. Hence, could you please extend your answer to "how would you add const correctness to C# if your life was depending on this feature"? Or would you rather die? – Patrick Fromberg Aug 29 '16 at 17:09
  • 36
    This answer is the reason why i sometimes hate C# design. The language designers absolutely sure that they are much more smart than other developers and try to excessively protect them from bugs. It is obviously that const keyword works only in compile-time, because in C++ we have direct access to memory and can do anything we want and have number of ways to get round const declaration. But no one do this in normal situations. By the way, 'private' and 'protected' in C# also provide no guarantee, becuase we can access these methods or fields using reflection. – BlackOverlord Aug 30 '16 at 15:53
  • 15
    @BlackOverlord: (1)The desire to design a language whose properties naturally lead developers to success rather than failure is motivated by *a desire to build useful tools*, not by a belief that the designers are smarter than their customers, as you conjecture. (2) Reflection is not a part of the C# language; it's part of the runtime; access to reflection is limited by the runtime's security system. Low-trust code is not granted the ability to do private reflection. The *guarantees* provided by access modifiers are for *low trust code*; high trust code can do anything. – Eric Lippert Aug 30 '16 at 16:02
  • 8
    C++'s `const` is not "deeply broken". Frequently misunderstood? Yes (sadly, the possibility of modification through a non-const alias that you pointed out still surprises far too many C++ programmers). Less useful than a guarantee that the referenced object won't change? Yes, clearly. const can't eliminate every bug, but that isn't a reason to abandon it. – j_random_hacker Jan 06 '17 at 01:06
  • 3
    For your counterargument against BlackOverlord's point about reflection to hold water, you're obliged to contend that all serious C# development is low-trust code. (The fact that C#'s "guarantee" of privacy is broken by something outside the language proper, while C++'s "guarantee" of constness is broken within the language by `const_cast()`, is a purely academic distinction from the programmer's point of view: at the end of the day, the "guarantee" is still broken.) – j_random_hacker Jan 06 '17 at 01:16
  • 2
    Did you spend multiple days tracking down a bug in a c or c++ program, because someone lied to you, or where did this useless rant come from? Not saying I wouldn't ban `const_cast` if I could and I do see the dangers of `mutable`, but nothing you said gives any reason why the concept was not implemented (properly) in c# (except maybe the very end: *"It's never been a very high priority feature"*). – MikeMB Jun 01 '17 at 19:09
  • 1
    is this really true ? Modifying a const object through a mutable view/reference is undefined behavior isn't it ? – AF_cpp Aug 31 '18 at 08:55
  • 4
    This answer elaborately illustrates some common misconceptions about constness. Constness is a stipulation to a *contract* between the author and the user of an interface, so that neither party can break the contract accidentally. You cannot accidentally cast away constness in a modern C++ compiler -- you have to stand on your head, with specific syntax. Anybody with access to the code can search for any cases of such casts. Proper application of constness eliminates bugs that can be very hard to find, and simplifies programming. (This from a guy who has done a lot of C++, Java, and C#) – Steve White Sep 20 '18 at 05:34
  • 2
    @AF_cpp Yes, it is. Sorry but this answer is terrible, can't believe it has so much upvote. What you say about C is totally wrong. This answer contain too much opinion contrary to fact and is not suitable for SO. – Stargateur Nov 13 '18 at 18:11
  • 1
    @Stargateur: Well then, I encourage you to write your own answer that you like better. Remember, the question is why C# does not have const, so make sure you answer that question. If what you really want to do is write an article that explains what const-ness in C is all about, maybe start a blog and write your article in that blog. – Eric Lippert Nov 13 '18 at 18:19
  • 2
    @EricLippert That not my point, your answer is wrong from the point of view of C. I know that Microsoft in general don't like C, that OK, but that don't allow you to write wrong thing about C. Critic your answer have no link with me doing my own answer. You are just saying "if your are not happy go away" it is a very wrong behavior on SO, I just comment to explain why I downvoted. Also, I see that C# 7.2 have something about that now maybe this will interest you, https://learn.microsoft.com/fr-fr/dotnet/csharp/write-safe-efficient-code. – Stargateur Nov 13 '18 at 18:27
  • 2
    I have not written anything wrong, and I am not at all encouraging you to go away. I'm doing the opposite: I'm encouraging you to write posts that educate others so that your knowledge can help us all. I appreciate the link to the new C# features, but I am already aware of them. They illustrate how to correctly and effectively design const-correctness by observing the problems with the C design I identified eight years ago when I wrote this answer, when we had no plans to add such a feature to C#. – Eric Lippert Nov 13 '18 at 18:32
  • 6
    What you might consider doing then is writing an answer to this question that illustrates how the new C# 7.2 features address the shortcomings of the const feature in C, and thereby answer the question that was asked. Sadly, I do not have time to do so myself, but plainly you feel strongly about this subject so I encourage you to spend some time expanding your thoughts into a helpful answer. – Eric Lippert Nov 13 '18 at 18:33
  • 4
    The answer is based on a total misunderstanding of C++ const reference pattern and against the right software engineering. Constness is a very powerful tool in C++ since it explicitly shows to the developer what a function does or does not do with an object passed by argument. It is true that it is not always easy to use correctly but it is one of most wide-spread pattern in C++. It protects the developers to make multi-threading mistakes, helps to understand the data-flow, improves the readability and it makes to code easier to be extended. And no, **nobody casts from const to non-const**. – Tibor Takács Nov 24 '18 at 08:54
26

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
  • 15,217
  • 2
  • 35
  • 45
  • 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 Jul 16 '10 at 08:38
  • 3
    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 Jul 16 '10 at 08:46
  • 1
    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 Jul 16 '10 at 09:30
  • @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 Jul 16 '10 at 11:44
  • 2
    It is enforced _inside_ the method so it wouldn't be a breaking change to introduce it in the BCL. – Rune FS Jul 16 '10 at 15:24
  • @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 Jul 16 '10 at 16:29
  • 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 Jul 16 '10 at 17:15
  • @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 Jul 16 '10 at 17:48
  • 1
    Even if the run-time couldn't enforce it, it would be helpful to have an attribute which specified whether a function should be allowed/expected to write to a `ref` parameter (especially, in the case of struct methods/properties, `this`). If a method specifically states that it will not write to a `ref` parameter, then the compiler should allow read-only values to be passed. Conversely, if a method states that it will write `this`, the compiler should not allow such a method to be invoked on read-only values. – supercat Jul 09 '13 at 23:05
  • Surely const is a purely compile-time feature and requires no support from the runtime? If a program containing 'const' compiles, you can remove 'const' everywhere it occurs (including libraries) and it will still compile to the same bytecode. Const correctness is just an additional level of type checking the compiler does statically. – Ed Avis Feb 21 '17 at 10:15
  • This is a far more satisfying answer...frustrating but satisfying – Assimilater Jun 27 '17 at 15:47
17

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
  • 437,863
  • 77
  • 675
  • 810
  • 1
    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 Jul 16 '10 at 15:43
  • It is worthwhile but needs to be done in a typesafe manner . The Deep /Shallow const you mention opens a whole can of worms. – user1496062 Apr 01 '14 at 00:09
  • In a c++ where references are actually manipulated, I can see your argument about having two types of const. However, in C# (where you have to go through back doors to use "pointers") it seems clear enough to me that there is a well-defined meaning for reference types (i.e. classes) and a well-defined albeit different meaning for value types (i.e. primitives, structs) – Assimilater Jun 27 '17 at 15:51
  • 5
    Programmers who can't understand const-ness shouldn't be programming in C++. – Steve White Sep 20 '18 at 05:39
11

This is possible since C# 7.2 (December 2017 with Visual Studio 2017 15.5).

For Structs and basic types only!, not for members of classes.

You must use in to send the argument as an input by reference. See:

See: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier

For your example:

....
static void TestMethod1(in MyStruct val)
{
    val = new MyStruct;  // Error CS8331 Cannot assign to variable 'in MyStruct' because it is a readonly variable
    val.member = 0;  // Error CS8332 Cannot assign to a member of variable 'MyStruct' because it is a readonly variable
}
....
static void TestMethod2(in int val)
{
    val = 0;  // Error CS8331 Cannot assign to variable 'in int' because it is a readonly variable
}
....
isgoed
  • 724
  • 6
  • 12
5

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
  • 99,783
  • 25
  • 219
  • 289
  • So you think MS considers like 'noise' to have const parameters in methods. – Incognito Jul 16 '10 at 08:40
  • 1
    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 Jul 16 '10 at 15:40
  • So as I understnd it, your argurment is that constness was left out of C# to keep it simple. Think about that. – Steve White Sep 20 '18 at 05:37