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".