12

In Java, final means a variable can only be assigned to once, but that assignment can happen anywhere in the program. In C#, readonly means a field can only be assigned in a constructor, which, IMO, is significantly less useful.

As we all know, C# was heavily influenced by Java design, but this difference has always puzzled me as being very odd. Does anyone know if there's a technical reason in the CLR that resulted in the less-useful behavior of C#'s readonly vs Java's final?

EDIT:

In response to the comments; I'd like to point out that I am well aware of the benefits of immutability, and I use it all over the place. I believe readonly is less useful than Java because of this:

public class Foo 
{
    private readonly int _bar;

    Foo()
    {
        _bar = 5;
    }
}

Whoops, I actually need to initialize that value in a helper method!

public class Foo 
{
    private readonly int _bar;

    Foo()
    {
        initialize()
    }

    private void initialize()
    {
        _bar = 5; //Can't compile because of semantics of readonly
    }     
}
MgSam
  • 12,139
  • 19
  • 64
  • 95
  • 39
    Your "less useful" is my "more safe". – Oded Feb 22 '13 at 14:58
  • 3
    What are the benefits of immutability? I think you'll find `readonly` can be significantly useful for the compiler. You question is inherently subjective. – Jodrell Feb 22 '13 at 14:58
  • 3
    You cannot assing value to a final varible anywhere in the program in java as well. If you are making a static final constant then you need to give value on the spot otherwise if you are making variable as a final then you can initiate it in the constructor. – ATR Feb 22 '13 at 15:00
  • @ankur.trapasiya I think OP meant that you can use `final` in Java on a local variable. Hence "anywhere." – Jesus is Lord Feb 22 '13 at 15:01
  • 1
    possible duplicate of [What is the equivalent of Java's final in C#?](http://stackoverflow.com/questions/1327544/what-is-the-equivalent-of-javas-final-in-c) – John Saunders Feb 22 '13 at 15:02
  • 4
    @JohnSaunders It is not a duplicate. He is not asking about the _equivalent of Java's final in C#_. He shows he already knows that. I think you didn't bother to read the question, as it is completely different. – Daniel A.A. Pelsmaeker Feb 22 '13 at 15:09
  • `readonly` can be assigned also on declaration, not only constructor. Not sure if there's any CLR reason, but this makes safer as constructor will be called just once (same for declaration) and gives you possibility to set it to different values according to the constructor called (helping with polimorfism, inheritance, [...] seems like its more "OOP" to me). After getting used, you'll see no reason to declare a `readonly` outside constructor, neither will find it "less useful" and, as @Oded said, more safe. – Retired_User Feb 22 '13 at 15:17
  • @Jodrell, I agree with you that the question is subjective. But I'm not sure compiler would benefit of `readonly` as you said, since `readonly` is not a compile-time constant (as `const` is), it's a runtime constant. http://msdn.microsoft.com/en-us/library/acdd6hb7.aspx – Retired_User Feb 22 '13 at 15:21
  • 1
    @Jodrell I asked if there was a **technical reason in the CLR** for readonly behaving this way. People here don't even bother to read. – MgSam Feb 22 '13 at 15:36
  • Maybe I was hasty, I voted for reopen, @Gmoliv As I recall, lipperts posts on immutability highlight some potential benefits, http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx – Jodrell Feb 22 '13 at 16:18
  • In that case that @WordsLikeJared is mentioning you have to give value of the final variable where it has been declared. So basically what i think it final is equivalent to readonly in all cases except public static final. for public static final there is const keyword in c#. additionally readonly can only be used with properties in c#.you can find it here http://shivasoft.in/blog/microsoft/csharp/final-keyword-in-c-sealed-with-const-and-readonly/ – ATR Feb 22 '13 at 16:21
  • 8
    This question is based on a **false premise** that you can initialize a final Java field anywhere in the class. You cannot do this! The second example won't compile in Java (using *final*) as well. – Caffé Mar 06 '15 at 17:16
  • 1
    @MgSam the example you have posted won't work in java as well. So I don't understand how readonly in C# is more restricted – rents Jul 12 '17 at 10:37

2 Answers2

21

There is a technical reason for the behavior of readonly: in the created assembly's metadata the field is marked with the initonly attribute that will ensure the field is not modified outside a constructor.1 However, while unverifiable, by taking the address of the readonly field it is still possible to change its value. Verifiable IL and C# will not allow you to do this.

At compile time it is impossible to enforce this for all methods, since the compiler would have to analyze all possible orders in which methods could be called. At runtime it would probably be a burden on the CLR and negative for performance if it had to check every field write whether it has been written to before. Instead, it is safer that C# and the CLR just don't allow the field to be assigned a value anywhere except in the carefully analyzed scope of a constructor.

In my opinion this does not make the readonly keyword any less valuable. I use it all over the place for fields whose value is provided only by the constructor (e.g. creating a list, or storing a constructor argument). C# will ensure that I won't change the field after that ever again, ensuring that I cannot accidentally set it to null or anything.

1) Thanks to Eric Lippert for pointing this out.

Daniel A.A. Pelsmaeker
  • 47,471
  • 20
  • 111
  • 157
  • @Virtlink Thank you for your answer. It's nice that not everyone just looks for excuses to close things. – MgSam Feb 22 '13 at 15:38
  • 1
    The first paragraph is wrong. You can modify a readonly field via Reflection, using only safe C# and verifiable IL. You can even change the value of `string.Empty` that way. Perhaps you meant *trusted code*, which is a completely different concept from *verifiable IL*. Untrusted code cannot use (most of) Reflection, but verifiable IL can. – Timwi Sep 17 '13 at 08:18
  • 3
    @Timwi You are correct, but when you bring reflection into the picture, all bets are off. I didn't mention it as it is not relevant to the question. That makes my first paragraph not _wrong_, at most _incomplete_. – Daniel A.A. Pelsmaeker Sep 17 '13 at 13:02
  • 1
    The curious thing is that Java final and C# readonly, for the sake of this question, work exactly in the same way: you cannot assign value to them anywhere in the class but only in the constructor or in its declaration – Caffé Mar 06 '15 at 17:25
  • @Caffé: That's only true for C#. In Java you can assign the value anywhere, but _only once_. You'd usually want to do that in the constructor for sanity's sake, but that's not required. You will get an exception if you try to assign it a second time, no matter where you do that. – Daniel A.A. Pelsmaeker Mar 06 '15 at 17:28
  • 1
    @Virtlink What java compiler have you been using? Check out the question's second example not working in Java: http://ideone.com/iq1EbV. – Caffé Mar 06 '15 at 17:48
  • "only by the constructor" is great for constructor based dependency injection. – granadaCoder Aug 29 '18 at 14:43
-1

This is an old question but I think it's worth noting that this doesn't work in Java 15:

public class Main
{
   final int testInt;

   public Main()
   {
      init();
   }

   private void init() 
   {
      testInt = 3;
   }
}

java: variable testInt not initialized in the default constructor

So it seems C# readonly and Java final behave the same way.

TheAgent
  • 1,472
  • 5
  • 22
  • 42