Where are the readonly/const in .NET?
Asked Answered
G

5

30

In C++ you'll see void func(const T& t) everywhere. However, i havent seen anything similar in .NET. Why?

I have notice a nice amount of parameters using struct. But i see no functions with readonly/const. In fact now that i tried it i couldnt use those keywords to make a function that promises to not modify a list being passed in. Is there no way to promise the caller that this function will never modify the contents of list? Is there no way to say to call code and say this list should never be modified? (I know i can clone the list or look at documentation but i like compile errors sometime)

Greylag answered 11/5, 2010 at 20:36 Comment(0)
T
44

Immutability is still an area where C# is maturing. So far, C# has not adopted the const semantics of C++ ... which I actually think is a good thing. The behavior of const in C++ often made it challenging to design class hierarchies that worked they way you wanted. It wasn't uncommon to see code peppered with const_cast<> to bypass constness where it wasn't desirable. Hopefully, the designers of C# will invent a simpler but still expressive alternative.

At present, there is no language feature that marks parameters or objects passed to methods as immutable. The best you can do is pass an an object using an interface (or better yet a wrapper) that only permits read operations.

For some of the standard collection in .NET you can use the ReadOnlyCollection wrapper, which encapsulated any mutable ICollection type within a read-only container.

Creating immutable types requires planning and awareness of the language features. For example, the readonly keyword is your friend. It allows you to declare members of a class or struct as immutable. Unfortunately, this immutability only applies to the reference, not the members of the referenced object. What this means is that you can declare:

private readonly int[] m_Values = new int[100];

public void SomeMethod()
{
    m_Values = new int[50]; // illegal, won't compile!
    m_Values[10] = 42;      // perfectly legal, yet undesirable
}

In the above example, the reference to the array is immutable, but the individual elements of the array are not. This behavior extends beyond arrays, of course.

A practice I've found helpful when designing immutable types, is to separate the immutable behavior into its own interface which is then implemented by a class that manages the data. The interface only exposes get properties and methods that are guaranteed not to mutate the state of the object. It is then possible to pass instances of your type to methods as parameters of that interface type. This is a weak form of immutability support - since the called method can often cast the reference to the mutable type. A better, but more cumbersome alternative, is to create a wrapper implementation that implements that same interface and maintains a reference to the actual instance (much like ReadOnlyCollection does). This is more work but provides a stronger guarantee for immutability.

The approach you choose to use depends on how important guarantees of immutability are, and how much time and effort you are willing to spend to get there.

If you're interested in reading more on this topic, Eric Lippert has an excellent series of articles on immutability in C#.

Thiazole answered 11/5, 2010 at 21:4 Comment(3)
I disagree with the statement " It wasn't uncommon to see code peppered with const_cast<> to bypass constness". C++ code that is peppered with const_cast indicates a fault in the code designer, not the language. In well designed code, const_cast is used extremely rarely, as a last resort to deal with legacy code that doesn't accept const parameters. (In the case of data members that are used for caching, the mutable keyword can be used). +1 anyway for the rest of the post.Templin
@Andrew Shepherd: I agree with you that well designed code should not often require const_cast, but in practice coding with or designing for constness was something that many junior developers have a hard time grasping. It's not something you see often taught in CS/CE courses; and when push comes to shove (translate: time is running out to get your work done), developers will rely on any means that makes their code work. It's unfortunate, but not uncommon. My larger point was that it'd be nice if the C# team could come up with a simpler scheme so that more developers could embrace it.Thiazole
@AndrewShepherd: Correct me if I'm wrong, but I think const-casting may also end up being required in situations where code may need to receive and store (actor, target) pairs whose supplier guarantees that any actor which modifies its target will only be paired with non-const target instances. If no actors modified their targets, or if no targets were const, then there would be no need for const-casting, but I don't think there's a way to create the concept that actors which modify their target will only be paired with non-const objects. Is there a way to do that nowadays?Colorless
R
7

There is no const modifier for method parameters in C#. If you want to have something similar to const guarantees you can use immutable types in your interfaces. For example, a method can accept an IEnumerable<T> instead of a mutable collection type. You can also look at ReadOnlyCollection.

Repository answered 11/5, 2010 at 20:39 Comment(3)
It's worth noting (in case the question op doesn't know) that you can pass a list directly to a method that expects an IEnumerableDivest
Can either of you tell me what the difference between IEnumerable and ReadOnlyCollection? I have a feeling that the only difference is IEnumerable can be typecast to a container then edited (or maybe via reflections? maybe not?) while ReadOnlyCollection can not?Greylag
@acidzombie24: IEnumerable is an interface that collection classes implement, allowing them to participate in the ecosystem of types whose content you can enumerate (iterate over). ReadOnlyCollection is a special wrapper class that composes (aggregates) an ICollection instance and exposes only read-only operations. Unfortunately, ROC still provides methods like Add and Remove but throws runtime exceptions when they are invoked - making immutability enforcement at compile time weaker than it could be. Much of LINQ, by the way, is built on the IEnumerable<T> interface.Thiazole
D
5

I have notice a nice amount of parameters using struct.

One thing worth mentioning here is that C# exaggerates the difference between struct and class as compared to C++, by exaggerating the difference between value types and reference types. In C#, all classes are reference types, and all structs are value types. In .Net, everything is passed by value by default.

The result of this distinction for value types is that all value types are copied when passed to a function. If you pass a struct to a function, you are guaranteed that function will not change your original struct because the function is only working with a copy. Adding const to such a parameter is silly.

Reference types are passed by value, too. Or, more specifically, the reference itself is passed by value. So you have a copy of the reference, but it points to (refers to) the same object. Thus, changes made to the object by the function will persist after the function exits.

On surface, adding a const option, at least for reference types, seems like a good idea. Where it gets a little murky is with side effects. Or, rather, how is this enforced? Obviously it's easy enough to say that your code can't use property setters. But what about other methods? Any method call might need to change the object. Even property getters might have a side effect that changes something (say you implement a security feature to note when something was last accessed). Are you going to deny read access to a property because of the side effect?

Divest answered 11/5, 2010 at 21:55 Comment(2)
Well, C++ has a mutable keyword https://mcmap.net/q/63972/-does-the-39-mutable-39-keyword-have-any-purpose-other-than-allowing-a-data-member-to-be-modified-by-a-const-member-function. I agree though that it will become complex if const was added but i personally havent needed to use the mutable. So complexity should be rare.Greylag
A const option on parameters would work if you could declare methods and property getters as const. If an object is passed as a const parameter, you would only call the const methods.Templin
P
1

The problem is that const correctness as used in C/C++ is only enforced by the compiler. And readily bypassed btw. The CLR actually enforces type safety in managed code, not the compiler. Necessarily so because the .NET framework supports many languages. The type system and interaction rules are laid out in the CLI, a common language infrastructure that needs to serve many goals and masters.

Const correctness is rare in current languages. Personally, I know of only C++, a language that is not ported to the CLI. Enforcing rules on languages that have nowhere near the syntax for them is difficult. Something as simple as unsigned integral types not being in the CLS left a notable mark on the design of the base assemblies.

Immutability (real, not faked with a compiler) keeps the MSFT teams thinking. It is popular, I know the C# team has been thinking about it. Good for concurrency, etcetera. Eric Lippert did a 11 part blog post series on it, kinda petered out though. Too big for one guy and his audience. If there will be a real move to getting it implemented, I trust them to think it through and make it work. Some day. Some language.

Paragon answered 11/5, 2010 at 21:40 Comment(0)
F
0

as I know this is not possible on a easy way. Maybe this article gives you some ideas:

http://www.c-sharpcorner.com/UploadFile/bulentozkir/PassingConstInCS11082005014622AM/PassingConstInCS.aspx

Fullbodied answered 11/5, 2010 at 20:42 Comment(1)
this one is also very useful: blogs.msdn.com/abhinaba/archive/2006/01/18/513906.aspxFullbodied

© 2022 - 2024 — McMap. All rights reserved.