Core9: readonly auto-properties
[This post is part of a series, "wish-list for future versions of VB"]
IDEA: Readonly auto-properties. We should allow read-only properties, which are backed by readonly fields, and can be set by either a property-initializer or through the existing "New ... With" syntax.
SCENARIO: You want your class to expose a collection, so that users can add or remove elements. But you don't want them to actually change the list object itself:
Property p As IList(Of Integer) = New List(Of Integer) From {1, 2, 3}
SCENARIO: You want to create a simple immutable record. Currently the language fights against you every step of the way. It could be as easy as this:
Class Point
ReadOnly Property x As Integer = From New
ReadOnly Property y As Integer = From New
End Class
Dim t As New Point With {.x = 15, .y = 27}
The first scenario would be translated into this by the compiler:
ReadOnly Property p As IList(Of Integer)
Get
Return _p
End Get
End Property
Private ReadOnly _p As IList(Of Integer)
Sub New()
_p = New List(Of Integer) From {1, 2, 3}
End Sub
The initialization code "_p = ..." would be injected into every constructor, as is done with the current auto-properties.
As for the second scenario, it is more awkward to implement. We could translate it into the following. It would be an error if the user had already provided a constructor.
Class Point
ReadOnly Property x As Integer
Get
Return _x
End Get
End Property
ReadOnly Property y As Integer
Get
Return _y
End Get
End Property
Private ReadOnly _x As Integer
Private ReadOnly _y As Integer
Sub New(ByVal x As Integer, ByVal y As Integer)
_x = x
_y = y
End Sub
End Class
Dim t As New Point2(x:=15, y:=27) With {}
The "New ... With" translation is interesting. What we could say is this: "With {.x=15, .y=27}" will set mutable properties "x" and "y" if they exist (for backwards compatibility). If they don't exist but there do exist readonly auto-properties of the same name, then they will be moved as named arguments into the constructor.
There is a lot of magic going on in translating the second scenario. It might be too much. We would also have to be careful that the user remains able to set attributes conveniently enough, e.g. for serialization.
The first scenario is also not quite answered properly. Usually when you expose an IEnumerable(Of T) you really intend wrap your own private mutable list as a ReadOnlyCollection(Of T), so as to prevent sneaky users from casting the IEnumerable(Of T) into an IList(Of T) and then modifying your list.
Users have also asked for a way to have private setters for auto-properties. It might be that this is a more useful scenario rather than readonly.
Provisional evaluation from VB team: This is a decent idea, one that we should consider against the other decent ideas. Readonly datastructures and immutable datastructures are a Good Thing. And we should invent syntax for them that's as easy or easier than the equivalent syntax for mutable data, so that users can "stumble into a pit of virtue".