tags:

views:

335

answers:

6

This question came up in the comments of this answer. The inability to have readonly properties was proposed as a potential reason to use fields instead of properties.

For example:

class Rectangle
{
   private readonly int _width;
   private readonly int _height;

   public Rectangle(int width, int height)
   {
      _width = width;
      _height = height;
   }

   public int Width { get { return _width; } }
   public int Height { get { return _height; } }
}

But why can't you just do this?

public int Width { get; readonly set; }

Edit (clarification): You can achieve this functionality in the first example. But why can't you use the auto-implemented property shorthand to do the same thing? It would also be less messy, since you wouldn't have to directly access the fields in your constructor; all access would be through the property.

+11  A: 

If you want to make a property "read only" as far as functionality is concerned, you do so by only supplying the get method, as you indicated in your post.

public int Width { get { return _width; } } 
public int Height { get { return _height; } } 

The compiler will even reference these as "read only" if you try to write to them.

Having an additional term of readonly for a property would clash with also providing the set method. It seems to be poor syntax to me, i.e. how does the person reading it (or the compiler, for that matter) know what takes precedence: readonly or set?

Furthermore, as was explained in the answer you referenced, readonly applies only to fields and limits writing to those fields to the instantiation of the class. With properties, you can't write to them (I don't think) even within the constructor if they only have a get method.

Ben McCormack
You're right that this provides the same functionality. That's why it was included as an example. My question is: Why can't you use the auto-implemented property shorthand to do the same thing? It would also be less messy, since you wouldn't have to directly access the fields in your constructor; all access would be through the property.
Matthew
@Matthew sure, perhaps the team responsible for the C# compiler *could* have gone that route, but wouldn't it be more confusing? As @Nate explained, you can have a property that is `readonly`, just not a automatic one, which makes sense. While it might be *possible* to achieve what you're talking about, I do imagine it would be confusing (I, for one, would be confused).
Ben McCormack
+2  A: 

Properties can be read-only, just not automatic properties.

Both get and set are required for automatic properties, and it makes no sense for a read-only property to have a set.

You can define a regular property as a read-only property by just defining the get - however, even if the requirement for both get and set for automatic properties didn't exist - the read-only property couldn't be automatically defined because you have to know the backing field to be able to set it's value internally (i.e. through the constructor).

I suppose there could be a template/macro or something defined in VS to generate the code this, but it couldn't be a part of the language itself.

Nate
+6  A: 

You can make an automatic property read only by specifying the private access modifier for set like so

public bool Property {get; private set;}

The setter is still defined but it is no longer visible outside the class where the property is defined. As an aside, it is sometimes useful to define the setter as internal so that properties can be easily set from within the same assembly, but not by external callers.

Crippledsmurf
This does not have the same semantics as `readonly`.
Jason
This is true, however, a property with no setter or a private setter is still going to produce a compile time error and prevent value modification, so unless there is something I'm missing readonly and the absence of a setter are functionally equivalent
Crippledsmurf
It won't prevent value modification inside the class from outside the constructor.
ICR
+9  A: 

Because the language doesn't allow it.

This may seem like a frivolous answer: after all, the language designers could have declared that if you used readonly on an automatic property then it would mean "the property is settable but only in the constructor".

But features don't come for free. (Eric Gunnerson expresses it as "Every feature starts with minus 100 points.") To implement read-only automatic properties would have required additional compiler effort to support the readonly modifier on a property (it currently applies only to fields), to generate the appropriate backing field and to transform sets of the property to assignments to the backing field. That's quite a bit of work to support something that the user could do reasonably easily by declaring a readonly backing field and writing a one-line property getter, and that work would have a cost in terms of not implementing other features.

So, quite seriously, the answer is that either the language designers and implementers either never thought of the idea, or -- more likely -- they thought it would be nice to have, but decided there were better places to spend their finite resources. There's no technical constraint that prevents the language designers and implementers providing the feature you suggest: the reasons are more about the economics of software development.

itowlson
It's Eric Gunnerson that says that: http://blogs.msdn.com/ericgu/archive/2004/01/12/57985.aspx. Otherwise, great post and the correct answer.
Jason
Thanks for the correction and link, Jason -- updated.
itowlson
It was the latter. This has been on the list since C# 3. We'd love to do it, but it has never been a high enough priority. We come up with literally hundreds of ideas for new language features and we only get to do a couple of them in each version.
Eric Lippert
+1  A: 

I think fundamentally the problem is that properties are merely syntactic sugar for a field with optional getter/setter methods. Automatic properties generate the backing field so they require the "setter" or there would be no way to set the value of the backing field. Since properties really map onto methods, not fields, it doesn't make any sense to make them readonly.

Even if allowed, readonly could only apply to automatic properties. For traditional properties, you can put arbitrary code in both the getter and the setter. Even if the setter were able to be invoked only in the constructor of the class, the getter could still mutate the value based on whatever logic you decided to put in it. This would wholly inconsistent with the concept of readonly, thus necessitating different syntax rules and support for automatic/traditional properties. Since there is a mechanism -- using traditional properties with only a getter defined AND a readonly backing field as in the referenced question -- I see no point in mucking up the property syntax and potentially introducing confusion for something with a fairly easy and straightforward implementation using the current language constructs.

tvanfosson
very good point - "Since properties really map onto methods, not fields, it doesn't make any sense to make them readonly."
Ben McCormack
@tvanfosson, @Ben McCormack: That is absolutely false. What's wrong with `public int Width { get; readonly set; }` mapping to `readonly int _width; public int Width { get { return _width; } }` and `Width = 17` being legal only in the constructor?
Jason
@Jason perhaps I'm missing something, but I don't understand what you're saying. I don't believe he (or I) is saying that you shouldn't set up properties that lack a `set` method (thus making them "readonly" when compiled). He's saying that the **keyword** `readonly` can only be applied to fields, not methods (and thus properties by extension).
Ben McCormack
@Jason -- again, it would only apply to automatic properties, since you can't enforce the semantics of readonly if you allow arbitrary code in the getter. That would make automatic properties fundamentally different in a way that's more than just a shorthand notation than traditional properties. IMO that's not worth it for the corner case that can be implemented with explicit readonly backing fields and no setter on the traditional property.
tvanfosson
I understand that is currently the case and I'm reading that sentence that you quoted as being an argument against adding such a feature to the language. And I'm saying no, it does make sense to give `readonly` additional context wherein it can apply to `set` in an auto-implemented property with the meaning that I gave in my previous comment. `public int Width { get; readonly set; }` would just mean "you can get this property, and I promise you its value is not going to change." What's wrong with that?
Jason
@Jason -- also, I think you are fundamentally misunderstanding that properties are really syntactic sugar for methods, not fields (or instance variables). It would make no sense to have a "readonly" method, i.e., a (non-constructor) method that can only be called when the object is created. Introducing such a beast just to support this corner case seems like a waste of effort.
tvanfosson
@tvanfosson: The difference is that in `public int Width { get; readonly set; }` the `readonly` is part of the interface of the defining class or struct. Without such a syntax the user has no way of knowing that `Width` is `readonly`. This would more clearly express the intent of the property.
Jason
@Jason - I think what I hear you saying is that it is ok to treat automatic properties different than traditional properties in this way (and, oh by the way, introduce a special type of method that can only be called from the constructor). I disagree. I don't see the value.
tvanfosson
@tvanfosson: No, please don't insult me. I absolutely understand that getters and setters are methods behind the scenes. If you believe I think that then you are misreading me.
Jason
@Jason - I'm not trying to insult you. I just don't see how given the current language constructs you expect to have a readonly method, which is really what you are asking for.
tvanfosson
@tvanfosson: Again, you're missing what I am saying. There is not currently a way to express to the user that the value of a property won't change. That would be the major difference between the way that you suggest to implement "readonly" properties using the language as its designed currently and what I am discussing.
Jason
@tvanfosson: I am not asking for a readonly method. I don't know why you keep suggesting that. Please look back at my first comment to your post where I proposed how `public int Width { get; readonly set; }` would be translated.
Jason
@Jason `set;` within an automatic property is shorthand for `set {ThisProperty = value;}` . i.e. `set` is a method. Perhaps I might be able to agree if the modifier looked like `set {readonly ThisProperty = value;}`, but then we don't have an automatic property anymore. If `set` is a method, and `readonly` doesn't apply to methods, it makes sense to me that `readonly` cannot be applied to `set`.
Ben McCormack
@Jason the problem with your syntax, IMO, is that the `readonly` modifier comes before `set` and you're then instructing the compiler to read the modifier of that method and map it to a field. To me, that's confusing.
Ben McCormack
@Jason -- ok so it's not **readonly**, it's **execute once**, because the setter is implemented as a method and you're promising that it will never be invoked after the first time and, then only in the constructor. Saves a line of code in a corner case that I suspect happens only rarely. Again, I don't see either the value or the ROI on creating it **and** it makes automatic properties behave in a way fundamentally different than traditional properties.
tvanfosson
@Ben McCormack: I understand what `set` for an automatic property is currently translated to. I'm saying translate it to something different when it's modified with `readonly`. I've already explained in my first comment to this post what it could be translated to.
Jason
@Jason I just searched through the entire C# spec. http://msdn.microsoft.com/en-us/vcsharp/aa336809.aspx. It's very clear that `readonly` is a *field-modifier*. If you were to put a `readonly` modifier in front of `set`, which is not a *field*, it would cease to be a **FIELD** modifier. I imagine the compiler team doesn't want to brek the spec by interpreting `readonly` out of the context of modifying a field. Beyond that, there's no reason why the example you gave doesn't make sense.
Ben McCormack
@Ben McCormack: Ben, the language can change. For example in C# 2.0 `where` could be used only for generic constraints (`class Foo<T> where T : Bar { }`). Now it can be used in query syntax (`from f in foos where bar(f) == 17 select frobber(f)`).
Jason
@Jason you are correct. It's possible that in the future the C# spec might change so that `readonly` is not exclusively a field-modifier. But for me, I'm going to try to focus on what C# *currently is*, and not what it *could be*. There's enough to grok already.
Ben McCormack
@tvanfosson: First, and again, you are missing that currently it is not possible to express to the user semantically that the value of a property won't change. Second, it would make designing immutable types much friendlier. Oh, how beautiful would `class Rectangle { public readonly double Height { get; readonly set; } public readonly double Width { get; readonly set; } }` be? Then: `Rectangle r = new Rectangle { Height = 2.718281828459045, Width = 3.1415926535 };` But now the user can see in the declaration of the properties that they are `readonly`.
Jason
Also, I realize way above I should have said `Width = 17` is legal only in the constructor or in the object initializer. Forgive me.
Jason
@Ben McCormack: That's fine, but I find that I understand the language better if I also understand what it is not currently, what it could be, and what features I would like to see. :-)
Jason
@Jason - we're arguing different points. I never said that the language couldn't be different or that the change wouldn't make some things easier. I am saying that to do so would only apply to auto properties, would make auto properties different than traditional properties in a fundamental way, and doesn't really add anything that using two lines instead of one (or a comment if in an API) would. I simply don't see enough value to make such a fundamental change in how properties are handled. I think in this case we need to simply agree to disagree.
tvanfosson
A: 

If the propert has a private set, then it is readonly from the outside world, i.e:

string _name;
public string Name
{
     get{ return _name; }
     private set { _name = value; }
}

Or, it can be made readonly if it doesnt have the setter at all, i.e.:

string _name;
public string Name
{
     get{ return _name; }
}
Bhaskar