Why Are Const Parameters Not Allowed in C#

Why are const parameters not allowed in C#?

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.

Const function parameter in C#

Update 16/09/2020

There now appears to be the in parameter modifier that exhibits this behaviour (in essence, a ref readonly). A brief search on when you would ever use this yields the following answer:

Why would one ever use the "in" parameter modifier in C#?

Original Answer

There is no equivalent for C# and it has been asked many, many, many, many times before.

If you don't want anyone to alter the "reference", or perhaps you mean the content of the object, make sure the class doesn't expose any public setters or methods of mutating the class. If you cannot change the class, have it implement an interface that only publicly exposes the members in a read-only fashion and pass the interface reference instead.

If you mean you want to stop the method from changing the reference, then by default if you pass it "by reference", you are actually passing the reference by value. Any attempt from the method to change what the reference points to will only affect the local method copy, not the caller's copy. This can be changed by using the ref keyword on a reference type, at which point the method can point the reference at a new underlying object and it will affect the caller.

Why is there no const member method in C# and const parameter?

First off, there is no requirement that we provide a reason for not implementing a feature. Features are extremely expensive; there has to be a justification for implementing a feature, not a justification for not implementing a feature.

Second, C# is not a clone of C++ or C. Just because a feature is in some other language is not a reason to put it in C#.

Third, "const" is deeply, tragically broken in C and C++. "const" gives you no guarantee that you can actually rely upon. If you are the caller of a method that takes a const reference then you have no guarantee whatsoever that the method honours the constness; the method has many ways of mutating a const reference. If you are the consumer of a const reference then you have no guarantee that the underlying object actually will not mutate arbitrarily. Since the contract is not enforced on either the caller or the callee side, it is far weaker than any other guarantee that we would like to make in the type system. We would not want to replicate such a broken system.

Fourth, putting constness in the CLR type system means that every language would have to use the same implementation of constness; since different languages have different meanings for constness, that would be making it harder to bring more languages to the CLR, not easier.

There are many reasons for not doing this extremely expensive feature, and very few reasons to do it. Expensive, unjustified features don't get implemented.

Can parameters be constant?

Unfortunately you cannot do this in C#.

The const keyword can only be used for local variables and fields.

The readonly keyword can only be used on fields.

NOTE: The Java language also supports having final parameters to a method. This functionality is non-existent in C#.

from http://www.25hoursaday.com/CsharpVsJava.html

EDIT (2019/08/13):
I'm throwing this in for visibility since this is accepted and highest on the list. It's now kind of possible with in parameters. See the answer below this one for details.

Read-only (const-like) function parameters of C#

I think you may be looking for a solution involving two interfaces in which one inherits from the other:

public interface IReadableFoo
{
IMyValInterface MyVal { get; }
}

public interface IWritableFoo : IReadableFoo
{
IMyValInterface MyVal { set; }
}

public class Foo : IWritableFoo
{
private ConcreteMyVal _myVal;

public IMyValInterface MyVal
{
get { return _myVal; }
set { _myVal = value as ConcreteMyVal; }
}
}

Then you can declare methods whose parameter type “tells” whether it plans on changing the variable or not:

public void SomeFunction(IReadableFoo fooVar)
{
// Cannot modify fooVar, excellent!
}

public void SomeOtherFunction(IWritableFoo fooVar)
{
// Can modify fooVar, take care!
}

This mimics compile-time checks similar to constness in C++. As Eric Lippert correctly pointed out, this is not the same as immutability. But as a C++ programmer I think you know that.

By the way, you can achieve slightly better compile-time checking if you declare the type of the property in the class as ConcreteMyVal and implement the interface properties separately:

public class Foo : IWritableFoo 
{
private ConcreteMyVal _myVal;

public ConcreteMyVal MyVal
{
get { return _myVal; }
set { _myVal = value; }
}

public IMyValInterface IReadableFoo.MyVal { get { return MyVal; } }
public IMyValInterface IWritableFoo.MyVal
{
// (or use “(ConcreteMyVal)value” if you want it to throw
set { MyVal = value as ConcreteMyVal; }
}
}

This way, the setter can only throw when accessed through the interface, but not when accessed through the class.

What's the idea behind allowing private constant to be used as default parameters for public methods?

The name DefaultValue is private, but the number 2 is still the number 2.

Because DefaultValue is private, we cannot access Program.DefaultValue from outside of Program. Presumably we wouldn't particularly want to.

And because we've bothered to define DefaultValue at all, it's presumably something that we do care about when we are working on how Program works.

So when we come to define a default value for DoSomething there's presumably some logical reason why the value we want there happens to be the same as the value DefaultValue.

And as such, it's presumably beneficial to be able to use that constant there, for much the same reasons as we would find constants beneficial anywhere.

And since DefaultValue is just a Program-specific way of saying 2, there's no real reason why we can't.

Of course, the metadata would reflect this as 2 rather than the (meaningless to the outside) DefaultValue, but then that would hold if the const was public anyway (the metadata about default values gives only the value, not whether or not it related to any defined constants).

So there's no downside.

So considering that:

  1. There's an advantage to the implementer.
  2. There's no disadvantage to the user, over just a use of a literal 2.
  3. Preventing it would have to introduce a special rule to be an exception to the rule that defined constants can be used anywhere a constant value from a literal can.

Why not?

const correctness in C#

I've come across this issue a lot of times too and ended up using interfaces.

I think it's important to drop the idea that C# is any form, or even an evolution of C++. They're two different languages that share almost the same syntax.

I usually express 'const correctness' in C# by defining a read-only view of a class:

public interface IReadOnlyCustomer
{
String Name { get; }
int Age { get; }
}

public class Customer : IReadOnlyCustomer
{
private string m_name;
private int m_age;

public string Name
{
get { return m_name; }
set { m_name = value; }
}

public int Age
{
get { return m_age; }
set { m_age = value; }
}
}

Why does the declaration of a DateTime const give a compiler error but not optional parameter?

Have a look at the msdn article on optional parameters.
When the data type is a value type (enum, struct) you may initiate an optional parameter with an empty constructor:

static void Foo(string s, DateTime opt = new DateTime())

Or with the default keyword. This isn't true for reference types.

C# 7.2 const vs referenced(in) readonly field in function parameters passing

I have do a test and the winner is the readonly field passed with in, this is the code executed with a i7 8700k processor

class Test
{
public const decimal x = 0.2m;
public readonly decimal y = 0.2m;

public void Method1(in decimal x)
{
Thread.MemoryBarrier();
}
}

class Program
{
static void Main(string[] args)
{
var t = new Test();

var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 100000000; i++)
{
t.Method1(in t.y);
}
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
sw.Restart();
for (var i = 0; i < 100000000; i++)
{
t.Method1(Test.x);
}
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
Console.ReadLine();
}
}

The method invoked as t.Method1(in t.y); have consumed 11606428 ticks,
The method invoked as t.Method1(Test.x); have consumed 16963941 ticks

So there are not optimizations under the hood for the const in this case

can a method parameter pass an object by reference but be read-only?

No. C# has no direct analogue to C++ const (its own const is something different). A common C# pattern for this is to pass in a interface, such as IEnumerable, that does not permit modifications. You can also create an immutable copy or wrapper.



Related Topics



Leave a reply



Submit