vars (lift’em all to the top-most scope). I can’t believe JS convinced the rest of us that it was okay. Then came ES6 and saved us.
let fixed the scoping.
Even a kid would tell you that the top 2 facets of functional programming are immutability and functions as first-class citizens viz. Higher Order Functions (HOF). The other facets are equally important but without the top two, there is no functional programming.
From day one, C# has supported the ability to treat functions as first-class citizens through
delegates. Yes, the concept of HOF wasn’t at its best in C# until the introduction of anonymous delegates or better lambdas later. But, hey, you were able to pass functions around as data.
That was one side of the coin – HOF. What about the other side – immutability? As you should know by now, Immutability is not a light subject.
It is a shame that even after 15+ years, C# doesn’t yet support immutability … fully.
C# supports (compile-time) constants (
const), and a partial or rather peculiar support for immutable variables (
readonly, you can only declare immutable member variables. It cannot be used with local variables or method parameters. But here’s the peculiar part.
readonlyis still mutable within the constructor.
I wonder why.
I am a big fan of immutability. The confidence that an immutable variable provides is irreplacable. Once you start declaring immutable variables – assignable only once, the complexity of your code / logic untangles and assembles itself in steps. Individual steps of your logic wire smoothly in a chain / pipeline allowing each step to be tested independently.
Immutability for C#
I have not read (any) proposals myself but heard rumors, once or twice, of adding support for immutable variables in C#. Like I said, I haven’t looked into the proposals, so I am dreaming here.
There are several ways to get C# support immutable variables.
… as in Scala or pairing up with C#’s own
Despite being succinct and using an establish convention, I don’t like this option because of two reasons:
varwas invented primarily for automatic type deduction or what C# calls implicit typing specifically for LINQ queries that return anonymous types. Although the C# team was smart in making it more or less general purpose, it might have been better named
auto. Since C# is not a purely functional language and is inherently imperative, it just so happens that
varnaturally got related to (mutable) variable.
varis restricted to local variables. It cannot be used as class members, method parameters etc.
varbe lifted outside function scope to class members and others so that
valbecomes an apt counterpart? In other words,
valshould be freely usable – local variables, members arguments etc. That won’t work because
varon parameters does not make sense (an indication that
valon class members overlaps with
varis not lifted, yeah maybe,
valmight work. Or maybe, not quite so. For instance, if we assign a LINQ query returning an anonymous type to a
val, we would expect
valto perform automatic type deduction. Although it is nice,
valnow is doing more than what we started with viz. immutable variables.
valwould appear to be an effort to appeal to the Scala community.
Like I said,
valpair up verbally but not in their purpose. There is definitely some noise around there.
… in parlance with F#’s
Of all the ways to declare variables, mutable and immutable, I like the F#’s most; better than
val. F# starts with immutable variables as its default and wants you to explicit state that you like to make a variable mutable, just like Scala. But the beauty of F# is having to decorate the default
mutablemaking it stand out visually.
// F# code let imCount = GetNoOfItems(); let mutable mutCount = GetNoOfItems();
Borrowing the idea, we could come up with an
// C# code int mutCount = GetNoOfItems(); immutable int imCount = GetNoOfItems();
Does the job. Besides being mouthful, what do we with
readonly? Two different keywords for essentially the same thing. This will be a catalyst for introducing yet another for immutable method parameters. Come on, this isn’t PHP 😂.
If thrown for a vote, I am sure this option would lose.
Reuse Existing Keywords/Quantifiers
A vehement No. A constant is different from an immutable variable. Any attempt to reuse will skew the meaning of existing conventions in C#. Case closed.
let was schooled for LINQ queries. Although the (intermediary) variables declared through
let are immutable[^1], it is not particularly obvious in an imperative language like C#. A
let in C# does not suggest the same thing as in F#.
Suppose we go with
let, do we make it an independent keyword or a modifier on existing variable declarations?
// C# code let immutableCount = GetNoOfItems();
// C# code let int imCount = GetNoOfItems();
I prefer the latter because the former is on the same boat as
val and implicit typing thing we discussed earlier. The latter seems to fit the bill. Just that
let has got this unintended feel of a lame copy from F# and poorly applied. Do we really want that blame?
If done right, this would be the perfect choice. Before dealing with the perfect side of it …
- Scope wise,
readonlyis the opposite of
varis stuck inside methods while
readonlyis stuck outside. Oh, lovers apart! Earlier we discussed about lifting
varoutside the function scope. Here, we like to get
readonlyinto function scope.
var is the equivalent of the actual type specifier (or the type auto-detected).
readonly is a modifier on a type specifier. So,
readonly goes well with
var too. Lovers meet. So,
readonly var imCount = … is as legit as
readonly int imCount = ....
readonly is equivalent of F#’s
mutable producing the reverse effect. A
readonly in C# makes a variable immutable while
mutable does the opposite in F#. Both are modifiers on variable declarations.
So, shall we declare
readonly the winner? Yes, but not quite. It is not a perfect choice yet. Because let us remind ourselves that
readonly is a peculiar one.
>If we make one breaking change of no longer supporting
readonly member variables mutable inside a constructor then
readonly should be the perfect choice.
I will argue that mutated
readonly member variables today can be rewritten to once-assigned and truly immutable variables. So, a breaking change here is truly for the win.
Other side of the fence
Languages that started out as functional first like Scala, F# and others are well-off; as far as immutability is concerned. On some level, I would say C++ too has got it covered; nevertheless beware of quirks.
Let us take a moment to interrogate the arch rivals we created – C# and Java.
Java started out with support for immutability but not HOF; until the introduction of lambdas in verion 8. So now, you can do functional programming in Java; or so they say.
On the other hand, C# started out with (a little crude) support for HOF and is still limping its way towards supporting immutability. No wonder, they are arch rivals. What an odd world we live in.
Needless to say, there should be other good options. Love to hear.
C# is a very carefully designed language. There is abunant written material to prove that. At the same time, it is man-made. So any limitations or shortcomings one should see should be seen with some love.
It is unfortunate that each language starts out with a certain flavor – imperative, OO, functional or whatever, and later finds itself struggling or unable to support other flavors.
A reasonable language should support and allow picking from a variety of widely practised paradigms, techniques and styles of programming and yield to the reasonable programmer to implement a solution that fits the problem.
Or so did Bjarne Stroustoup say (something similar), of course quoting C++. He was right in every way.