28

I've been wondering for a while why C# doesn't support const on a class or a method level. I know that Jon Skeet have wanted support for immutability for a long time, and I recon that using the C++ syntax of function const could aid in that. By adding a const keyword on a class level we would have total support.

Now, my question is, what the reason is for the C# team to not have developed this kind of support?

I'd imagine everything could be created with a compile-time check or through attributes, without needing to change the CLR. I don't mind code being able to override the const behavior through reflection.

Imagine this:

const class NumberContainer
{
    public int Number { get; }
}

.. Such a class could only be populated at construction time, so we'd need a constructor to take in an int.

Another example is const on a method-level:

public int AddNumbers(NumberContainer n1, NumberContainer n2) const
{
   return n1.Number + n2.Number;
}

Const-level methods should not be able to alter state in their own class or instances of reference types passed to them. Also, const-level functions could only invoke other const-level functions while in their scope.

I'm not really sure if lambdas and delegates would make everything too hard (or impossible) to achieve, but I'm sure someone with more experience in language and compiler design could tell me.

As Steve B pointed out in the comments, the existence of readonly makes things a bit more complex, as const and readonly are close to the same during runtime, but readonly values can't be determined during compile-time. I guess we could have const and readonly level but that might be too confusing?

So, what's the reason for not implementing this? Usability concerns (understanding constness in C++ usually quite hard for new users), language design concerns (can't be done) or simply priority concerns (the days of the immutability-buzz are over)..?

cwap
  • 11,087
  • 8
  • 47
  • 61
  • doesn't the `readonly` keyword handle your requirement ? – Steve B Apr 11 '12 at 07:38
  • Oups, my bad.. I had a lot of thought about readonly as well, but forgot to post it. Will update my thought-process.. – cwap Apr 11 '12 at 07:39
  • 8
    You are basically asking "why doesn't the language have feature X" - simple: either it hasn't been proposed + considered + approved + scoped + designed + implemeted + tested + documented + deployed (weighed against other possible uses for that resource, and the impact of language bloat), or *some* of that was considered and it was rejected as undesirable, or deferred. It is not automatic that every language gets every feature imaginable. – Marc Gravell Apr 11 '12 at 07:40
  • @MarcGravell Meta+1, though obviously the question might be asking what the reason is for the decision, the first thing that pops into my head with these sorts of questions is "just because". – Adam Houldsworth Apr 11 '12 at 07:50
  • 2
    @Adam indeed "because it wasn't a good enough use of time to make the cut" is a reasonable first assumption. [Eric Lippert also adds notes here](http://blogs.msdn.com/b/ericlippert/archive/2009/06/22/why-doesn-t-c-implement-top-level-methods.aspx). – Marc Gravell Apr 11 '12 at 07:51
  • @MarcGravell I haven't yet had enough cups of tea this morning to understand an Eric Lippert blog post... lol – Adam Houldsworth Apr 11 '12 at 07:52
  • This is also addressed at the bottom of this **question**: http://stackoverflow.com/questions/1370042/why-is-const-correctness-specific-to-c ; see the quote from Anders – Marc Gravell Apr 11 '12 at 07:55
  • 1
    I understand that implementing stuff is expensive, and I understand that other features might have a higher priority. I was simply trying to understand the consequences of implementing a feature like this, and why it would be so expensive and (maybe) not significant enough.. – cwap Apr 11 '12 at 08:41
  • I clearly don't understand `const` in C++ – Jodrell Apr 11 '12 at 10:32

6 Answers6

28

Risking a somewhat circular explanation, C# doesn't support const because the CLR has no support for it whatsoever. The CLR doesn't support it because it is drastically non-CLS compliant.

There are very few languages that have the concept. The C language has support for const, that's well supported in C# by readonly keyword. But the big dog is of course C++ that has a much wider applicability for const, no doubt the one you are looking for. I'll avoid pinning down what const should mean, that's a wormhole in itself and just talk of "const-ness", the property of having const applied.

The trouble with const-ness is that it needs to be enforced. That's a problem in C# when an arbitrary other language can use a C# class and completely ignore const-ness just because the language doesn't support it. Bolting it onto every other CLS language just because C# supports it is of course very unpractical.

Enforceability is a problem in C++ as well. Because the language also supports const_cast<>. Any client code can cast the const-ness away swiftly and undiagnosably. You are not supposed to, but then sometimes you have to. Because there are two kinds of const-ness, strict and observable. Roughly analogous to private const-ness and public const-ness. The mutable keyword was added to the language later to try to deal with the need for observable const-ness so at least the inevitable usage of const_cast<> could be avoided. Some people say that C++ is a difficult language. Don't hear that of C# much.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
3

You say the CLR wouldn't need to be changed, but consider that there's no standard way to express this "const"ness within compiled assemblies - and that these assemblies might not be consumed by C# code anyway. It's not something you can just do for C# - you'd have to do it for all .NET languages.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
2

As I believe the case to be, const means different things in C# compared to C++.

In C# you can use the readonly keyword to get the level of functionality you're wanting from const.

Jamie Dixon
  • 53,019
  • 19
  • 125
  • 162
2

I was once surpised by the following situation:

class Vector
{
    private double[] m_data;
    public int Dimension {get;set;}

    public double this[int i]
    {
        get {return m_data[i];}
        set {m_data[i] = value;}
    }

    public Vector(int n)
    {
        this.Dimension = n;
        this.m_data = new double(n);
    }

    public static Vector Zero(int n)
    {
        Vector v = new Vector(n);
        for (int i = 0; i < n; i++)
        {
            v[i] = 0.0;
        }

        return v;
     }

    public static readonly Vector Zero3 = Zero(3);
}

Thou Vector.Zero3 is readonly and you cannot assign to it, you can still access its component, and then the following stupid thing happens:

Vector a = Vector.Zero3;
a[0]     = 2.87;

and now, since a ist nothing but a reference to Vector.Vector3 the latter also has Vector.Vector3[0] == 2.87!

After I fell into this pit once, I invented a very simple hack, though not being elegant, fulfills its function.

Namely, into a class that I suppose to produce static readonly "constants", I introduce a Boolean flag:

class Vector
{
    private double[] m_data;
    public int Dimension {get;set;}
    private bool m_bIsConstant = false;
    ...

    public double this[int i]
    {
        get {return m_data[i];}
        set 
        {
           if (!m_bIsConstant)
           {
                m_data[i] = value;
           }
        }
    }
    ...
    public static Vector Zero(int n)
    {
        Vector v = new Vector(n);
        for (int i = 0; i < n; i++)
        {
            v[i] = 0.0;
        }

        v.m_bIsConstant = true;
        return v;
     }
     ...
}

This hack guarantees that your static readonly variable will never be modified.

1

In the case of your proposal for a const-class, you say:

Such a class could only be populated at construction time, so we'd need a constructor to take in an int

But by making all properties read-only anyway you have already achieved what you've said.

I cannot speak for the C# language designers but maybe the reason of not having const applied to lots of other constructs is because adding it was simply not worth the effort and you can get around the issue in other ways (as described above and in other answers/comments).

Peter Monks
  • 4,219
  • 2
  • 22
  • 38
1

I can't tell from your question, how this overloading of the const keyword would be especially beneficial.

Your first example could be rewritten legally as

public class NumberContainer
{
    private readonly int number;

    public NumberContainer(int number)
    {
        this.number = number;
    }

    public int Number
    {
        get { return number; }
    }
}

Perhaps, if the compiler is unable to discern the immutability of this class (I don't know), some attribute could be useful?

In your second example, I do not understand what you are driving at. If a function returns a constant value then it can be replaced with a constant field.

Jodrell
  • 34,946
  • 5
  • 87
  • 124