I use C# in production. It's a great language. It has implemented a lot of really powerful features like pattern matching and linq. If I was going to change one thing about C#, it would be to make variables immutable by default. Rust does this really well, and I'm considering Rust as one of my favorite languages because of this. Here's how I arrived at this being my favorite Rust feature and what I think it would look like for C# to implement something like this.
My short story
Everyone on my team would agree that important transformations should not be hidden by side effects. Likewise, that immutability is generally a good practice. However, any code base will start to age after a number of years, so you if the compiler allows you to do something, you can probably find an example of it.
I found one such example working through a bug:
// line 1
var tags = new List<tag>();
var editedLines = lines.Where(line => line.IsEdited);
// ...line 200
var transformedEditedLines = TransformEditedLines(editedLines, parameter2, parameter3, tags);
// ...line 400
Submit(transformedEditedLines, transformedNewLines, tags);
The bug said that the tags were being set wrong. It took me a long time to figure out where the tags were even being set. There was no method for it, yet by the time it got to Submit(), they were there.
As you can guess by the lines I've included, they were being set in TransformEditedLines(). You can understand my confusion because it looks like TransformEditedLines() is a pure function which takes in the parameters it needs and spits out the lines after they're transformed.
Why default immutability would help
First, when you're writing the code, you would start to default to setting it in the place of initialization. That would decrease that chance that anyone would write this mutable mess out of convenience.
Secondly, when you're reading the code, you would know from the definition whether to look out for a mutable mess. There would be an assumption of side effects, so even functions that pure would raise a warning flag.
Here's roughly what this could look like in C#:
// line 1
// notice the "mut" mutable keyword.
var mut tags = new List<tag>();
var editedLines = lines.Where(line => line.IsEdited);
// ...line 200
// notice the "mut" keyword here too.
var transformedEditedLines = TransformEditedLines(editedLines, parameter2, parameter3, mut tags);
// ...line 400
Submit(transformedEditedLines, transformedNewLines, tags);
Adding "mut" would be a lot like adding "private" to a field or "ref" to a parameter.
Where to go from here
What is your favorite Rust feature? What else could C# learn from Rust? Do you disagree? Is default immutability a bad thing?
Read about immutability in Rust: Rust docs
Top comments (7)
I know nothing about Rust, but I have been working with .Net for the last decade or so.
c# is very welcoming to the concept of immutability - c#7 introduced readonly structs, for instance, c#9 introduced a couple of very interesting features regarding immutability - One is the concept of "record" (that finally made it into the language) and the other is
init
auto properties, meaning you no longer have to write explicit constructors to get immutable properties.Also, C# supports local constants for a very long time now - and constant fields from day 1.
To sum up - c# supports immutability and that support gets better in each language version .
Also, the very concept of immutable variables is, IMHO, an oxymoron.
I mean, the meaning of the word "variable" in English is "subject to change"...
If you want something to be immutable, use the already provided readonly options.
Yes! I'm very interested in the "with" keyword in particular. The difference for me is what the default is, but you're right. There are good immutable options for C#
Immutability by default is a great thing, I think. This is one reason I prefer functional languages for a number of tasks (F#, Clojure etc).
The example you provided is a good one and this kind of bug have caused a lot of frustration in some codebases.
Conventions are nice for this, but enforced by the language is much better. It should also be an easy path to take compared to messing with side effects, preferably.
Thank you :). Yeah, it was a surprising amount of time to figure it out.
It's interesting how many good ideas are starting to be forced by newer languages - default immutability being one of them. I'm really looking forward to a day when these "good things" are as common as a language being more readable than assembly.
Immutability by default is a great thing. It solves thousands of problems.
I like Rust but there are huge problems. But I still couldn't get my head around circular dependencies and types. Somehow Rust started to look stupid to me when I was doing some really complex circular dependencies. C#, Java, even C++ have them really well. In Rust I started to feel like I had to remember each and every declaration of my structs and their members. This brought productivity down to zero. It didnt make sense anymore to use Rust. rust-unofficial.github.io/too-many... is a good example to exemplify this point.
Rust has one of the best communities around though. I have never seen human beings working with such unison to push an initiative (Rust) forward.
Also, I am working with microcontrollers these days. I dont see why I should ever use Rust there instead of C. Immutability is expensive there. It comes at a cost.
I would really love to hear from you if you think I am thinking/coding in the wrong direction.
I'll have to look out for that as I'm learning more about rust :)
Cool. Its a good language. Taught me a lot about programming. I just didnt feel like a good fit for me. I somehow prefer Nim.
Anyways, once you make a project in Rust or you are stuck somewhere, do go through this small book:
rust-unofficial.github.io/too-many... . Its just awesome.