"Const Correctness" in C#

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; }
}
}

Const correctness in C# with rich types

Can you get immutability in C#? Sure, if you design for it. You can do creative things with interfaces, and so on, to only expose the get of properties and none of the mutable methods.

That said, keep in mind there is nothing that prevents a crafty user from casting it back to the actual type (of course, same could be said of C++, you can cast away const-ness).

ISomeReadOnlyInterface readOnly = new SomeFullObject();

// hah, take that read-only interface!
((SomeFullObject)readOnly).SomeMutatingMethod();

Same with collections. Even if you return a ReadOnlyCollection (which prevents mutating behaviors on the collection itself) the data in the collection is still mutable (as long as the type allows it of course).

So I'm afraid there's really no simple answer here. There's no "flip-a-switch" const that gives you what C++ does.

It's really up to you, you can:

  • Design your types to be immutable and return iterators (or other read only sequences) instead of mutable collections.
  • Return new copies each time so that if they alter them it's no biggie.
  • Just return the actual data and leave tampering behavior as "undefined".
  • etc...

The latter is what collections like Dictionary<TKey, TValue> do. There's nothing that says you can't make the key type a mutable type (but woe if you do), and the MSDN is pretty clear that if you alter the key in such a way that it's hash code changes, it's on your own neck...

For my own work, I tend to keep it simple unless there is actually a big concern my class may be altered in a way that would cause side-effects. For example, if I'm storing web service results in a cache, I'll return a copy of the cached item instead so that if a user modifies the result they won't inadvertently modify the cached value.

So, long and the short of it is that I wouldn't worry about const-correctness of every type you return, that's just way too much. I'd only worry about things that you return that, if altered, could create a side-effect to other users.

How does const correctness help write better programs?

A whole section is devoted to Const Correctness in the FAQ. Enjoy!

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.

How may I return a const reference to an object from a method?

You can use interfaces to surface only getters while still supporting setters in the class that implements the interface. As long as you return the interface, any consumer will be restricted to only the getters that interface defines.

public interface IItem {
string SomeProperty { get; }
}

public class Item : IItem {
public string SomeProperty { get; set; }
}

public class ItemHandler {
private Item _item = new Item();

public IItem getItem() {
_item.SomeProperty = "A Value";
return _item;
}
}

class Program {
static void Main(string[] args) {
var itemHandler = new ItemHandler();
var item = itemHandler.getItem();

// You can read the property
Console.WriteLine(item.SomeProperty);

// You can't write to the property
//item.SomeProperty = "A New Value";
}
}

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 doesn't C# offer constness akin to C++?

I suspect there are some practical reasons, and some theoretical reasons:

  • Should the constness apply to the object or the reference? If it's in the reference, should this be compile-time only, or as a bit within the reference itself? Can something else which has a non-const reference to the same object fiddle with it under the hood?
  • Would you want to be able to cast it away as you can in C++? That doesn't sound very much like something you'd want on a managed platform... but what about all those times where it makes sense in C++?
  • Syntax gets tricky (IMO) when you have more than one type involved in a declaration - think arrays, generics etc. It can become hard to work out exactly which bit is const.
  • If you can't cast it away, everyone has to get it right. In other words, both the .NET framework types and any other 3rd party libraries you use all have to do the right thing, or you're left with nasty situations where your code can't do the right thing because of a subtle problem with constness.

There's a big one in terms of why it can't be supported now though:

  • Backwards compatibility: there's no way all libraries would be correctly migrated to it, making it pretty much useless :(

I agree it would be useful to have some sort of constness indicator, but I can't see it happening, I'm afraid.

EDIT: There's been an argument about this raging in the Java community for ages. There's rather a lot of commentary on the relevant bug which you may find interesting.

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.



Related Topics



Leave a reply



Submit