Why does C# disallow readonly local variables?

C#ImmutabilityLanguage DesignReadonly

C# Problem Overview


Having a friendly debate with a co-worker about this. We have some thoughts about this, but wondering what the SO crowd thinks about this?

C# Solutions


Solution 1 - C#

I think it's a poor judgement on part of C# architects. readonly modifier on local variables helps maintain program correctness (just like asserts) and can potentially help the compiler optimize code (at least in the case of other languages). The fact that it's disallowed in C# right now, is another argument that some of the "features" of C# are merely an enforcement of personal coding style of its creators.

Solution 2 - C#

A proposal readonly locals and parameters for was briefly discussed by the C# 7 design team. From C# Design Meeting Notes for Jan 21, 2015:

> Parameters and locals can be captured by lambdas and thereby accessed concurrently, but there's no way to protect them from shared-mutual-state issues: they can't be readonly. > > In general, most parameters and many locals are never intended to be assigned to after they get their initial value. Allowing readonly on them would express that intent clearly. > > One problem is that this feature might be an "attractive nuisance". Whereas the "right thing" to do would nearly always be to make parameters and locals readonly, it would clutter the code significantly to do so. > > An idea to partly alleviate this is to allow the combination readonly var on a local variable to be contracted to val or something short like that. More generally we could try to simply think of a shorter keyword than the established readonly to express the readonly-ness.

Discussion continues in the C# Language Design repo. Vote to show your support. https://github.com/dotnet/csharplang/issues/188

Solution 3 - C#

Addressing Jared's answer, it would probably just have to be a compile-time feature - the compiler would prohibit you from writing to the variable after the initial declaration (which would have to include an assignment).

Can I see value in this? Potentially - but not a lot, to be honest. If you can't easily tell whether or not a variable is going to be assigned elsewhere in the method, then your method is too long.

For what it's worth, Java has this feature (using the final modifier) and I've very rarely seen it used other than in cases where it has to be used to allow the variable to be captured by an anonymous inner class - and where it is used, it gives me an impression of clutter rather than useful information.

Solution 4 - C#

It is an oversight for c# language designer. F# has val keyword and it is based on CLR. There is no reason C# can't have the same language feature.

Solution 5 - C#

One reason is there is no CLR support for a readonly local. Readonly is translated into the CLR/CLI initonly opcode. This flag can only be applied to fields and has no meaning for a local. In fact, applying it to a local will likely produce unverifiable code.

This doesn't mean that C# couldn't do this. But it would give two different meanings to the same language construct. The version for locals would have no CLR equivalent mapping.

Solution 6 - C#

I was that coworker and it wasn't friendly! (just kidding)

I would not eliminate the feature because it's better to write short methods. It's a bit like saying you shouldn't use threads because they're hard. Give me the knife and let me be responsible for not cutting myself.

Personally, I wanted another "var" type keyword like "inv" (invarient) or "rvar" to avoid clutter. I've been studying F# as of late and find the immutable thing appealing.

Never knew Java had this.

Solution 7 - C#

I would like local readonly variables in the same manner as I like local const variables. But it has less priority than other topics.
Maybe its priority is the same reason for C# designers to not (yet!) implement this feature. But it should be easy (and backward compatible) to support local readonly variables in future versions.

Solution 8 - C#

Readonly means the only place the instance variable can be set is in the constructor. When declaring a variable locally it doesn't have an instance (it's just in scope), and it can't be touched by the constructor.

Solution 9 - C#

I know, this doesn't answer the why to your question. Anyway, those reading this question might appreciate the code below nonetheless.

If you are really concerned with shooting your self in the foot when overriding a local variable that should only be set once, and you don't want to make it a more globally accessible variable, you could do something like this.

    public class ReadOnly<T>
    {
        public T Value { get; private set; }

        public ReadOnly(T pValue)
        {
            Value = pValue;
        }

        public static bool operator ==(ReadOnly<T> pReadOnlyT, T pT)
        {
            if (object.ReferenceEquals(pReadOnlyT, null))
            {
                return object.ReferenceEquals(pT, null);
            }
            return (pReadOnlyT.Value.Equals(pT));
        }

        public static bool operator !=(ReadOnly<T> pReadOnlyT, T pT)
        {
            return !(pReadOnlyT == pT);
        }
    }

Example usage:

        var rInt = new ReadOnly<int>(5);
        if (rInt == 5)
        {
            //Int is 5 indeed
        }
        var copyValueOfInt = rInt.Value;
        //rInt.Value = 6; //Doesn't compile, setter is private

Maybe not as less code as rvar rInt = 5 but it works.

Solution 10 - C#

You can declare readonly local variables in C#, if you're using the C# interactive compiler csi:

>"C:\Program Files (x86)\MSBuild\14.0\Bin\csi.exe"
Microsoft (R) Visual C# Interactive Compiler version 1.3.1.60616
Copyright (C) Microsoft Corporation. All rights reserved.

Type "#help" for more information.
> readonly var message = "hello";
> message = "goodbye";
(1,1): error CS0191: A readonly field cannot be assigned to (except in a constructor or a variable initializer)

You can also declare readonly local variables in the .csx script format.

Solution 11 - C#

Being able to make local variables readonly makes it a lot easier to understand complicated algorithms, since it reduces the number of moving parts.

Since C# doesn't offer it natively for non-compile time constants I use this with implicit casts:

public readonly struct ReadonlyVar<T>
{
	private readonly T value;

	internal ReadonlyVar(T _value) => value = _value;

	public static implicit operator T(ReadonlyVar<T> _readonly) => _readonly.value;

	public override string ToString() => "" + value;
}

public static class ReadonlyExt
{
	public static ReadonlyVar<T> Readonly<T>(this T _value) => new ReadonlyVar<T>(_value);
}

Usage:

int y = 234;
var x = ( 9000 + y ).Readonly();
y = x;

It is not perfect, since it is possible to assign another ReadonlyVar to it, but this never happened to me unintentionally.

Solution 12 - C#

use const keyword to make read only variable.

reference: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/const

public class SealedTest
{
    static void Main()
    {
        const int c = 707;
        Console.WriteLine("My local constant = {0}", c);
    }
}

Solution 13 - C#

I think that's because a function that has a readonly variable may never be called, and there's probably something about it going out of scope, and when would you need to?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionBrian GenisioView Question on Stackoverflow
Solution 1 - C#andriejView Answer on Stackoverflow
Solution 2 - C#Colonel PanicView Answer on Stackoverflow
Solution 3 - C#Jon SkeetView Answer on Stackoverflow
Solution 4 - C#Derek LiangView Answer on Stackoverflow
Solution 5 - C#JaredParView Answer on Stackoverflow
Solution 6 - C#MikeView Answer on Stackoverflow
Solution 7 - C#brgernerView Answer on Stackoverflow
Solution 8 - C#Jason PunyonView Answer on Stackoverflow
Solution 9 - C#Mike de KlerkView Answer on Stackoverflow
Solution 10 - C#Colonel PanicView Answer on Stackoverflow
Solution 11 - C#Christian TeisterView Answer on Stackoverflow
Solution 12 - C#Derek LiangView Answer on Stackoverflow
Solution 13 - C#scottmView Answer on Stackoverflow