BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News Easier Immutable Objects in C# and VB

Easier Immutable Objects in C# and VB

Leia em Português

Bookmarks

A common pain point in .NET programming is the amount of boilerplate code necessary to implement immutable objects. Unlike a normal class, and immutable class requires that each property have an explicitly defined backing store. And of course a constructor is needed to tie everything together.

Under a new draft specification, C# and VB will be adding what they are calling a “record class”. This is essentially an immutable class defined solely by its constructor. Here is an example from the specification:

public record class Cartesian(double x: X, double y: Y);

In addition to the constructor, the compiler will automatically create:

  • A read-only property for each parameter
  • An Equals function
  • A GetHashCode override
  • A ToString Override
  • An “is” Operator, known as “Matches” in VB

The “is/Matches” operator is used in pattern matching, which we will cover in tomorrow’s article. Aside from that, record classes are a lot like C# anonymous types. (VB anonymous types differ in that they are mutable by default.) Microsoft is looking into ways to reconcile the two concepts, especially given the current limitation about not exposing anonymous types beyond their current assembly.

A common feature of immutable types is the ability to create copies of the object with one or more fields updated. Though not in the specification yet, here is one option they are considering for C#.

 

var x1 = new MyRecord(1, 2, 3);

var x2 = x1 with B: 16;

Console.WriteLine(x2) // prints something like "A = 1, B = 16, C = 3"

Extending Record Classes

In the Cartesian example class, you may have noticed that it ended with a semi-colon. This is to indicate that the class has no body other than what the compiler provides.

Instead of the semi-colon you can provide a set braces like you would for a normal class. You would still get the same compiler-generated code, but have the ability to add additional properties and methods as you see fit.

Other Limitations

For the time being only record classes are supported. In theory, record structs could be added using the same basic syntax and concepts.

Library Concerns

A serious limitation of immutable types in .NET is the lack of library support. Imagine that you are a middle tier developer. Your normal day-to-day tasks probably involve asking an ORM for some objects out of the database, which you then serialize as SOAP-XML or JSON for a one-way or round-trip to the client.

Currently most ORMs and serializers don’t have support for immutable types. Instead, they assume there will be a parameterless constructor and mutable properties. If this issue isn’t resolved in the more popular frameworks, record classes will be of little use in most projects.

For more information, see the draft specification Pattern Matching for C#. A prototype should be available in a few weeks.

Correction: This report erroneously stated that this feature would be part of C# 6 and VB 12.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • I like it

    by Joe Enos,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I think I like the idea - I'm sure there will be some way to deal with serialized data or data readers, either in the framework or shortly after in a third-party package.

    Maybe a static Record.FromXml(string xml) method with a generic parameter representing the specific record class (and another one for JSON, IDataReader, DataRow, IDictionary, FormCollection, etc.). As long as the names in the raw data line up to the properties, these should be pretty easy to build with a little reflection.

    If they build enough of these translators, then I'd expect any third party library that does normal object hydration could be easily extended or enhanced to use these record classes.

    Not sure I like the "with" syntax though - seems to me like it would be confusing to look at. If they can find a way to use more traditional code, it might look something like:

    // instead of
    var x2 = x1 with B: 16;

    // maybe one of these
    var x2 = x1.Copy(new { B = 16 });
    var x2 = x1.Copy(o => { o.B = 16; });
    var x2 = Record.CreateCopyFrom(x1, B: 16);

  • Time to take a look at F#

    by Arturo Hernandez,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    F# is a fully functional language, with C# interop support baked in. When you program in F# the inference engine specifies all the types for you. Only at the edges when you get an int from a user or a string from a file, are your types fully defined. And of curse everything is immutable by default. And there are mutable types in case you need them.

    I can't really list all the benefits here but, if you are reading this article chances are you should take a look at F#.

  • Library concerns

    by Roger Johansson,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I don't agree with the lib concerns.
    Since this is immutable types, you will not use them for "fat" entities, since they are not mutable.
    So the only thing you could use them for in an ORM, is projections, and the libs do support selecting projections.
    e.g.

    .Select(e => new MyRecord(e.Name,e.Age));

    So, it will still be of good use if you need projections with known types instead of anonymous types.

  • Looks great!

    by Ian Yates,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I've been using the ImmutableCollections & a project called ImmutableObjectGraph by one of the BCL devs from Microsoft (github.com/AArnott/ImmutableObjectGraph/) to achieve something similar with T4 templates for code generation.

    I've been able to teach JSON.Net how to handle these objects without too much fuss as well.

    When my code assistance tool (at the moment Telerik's JustCode because I get it with the GUI components subscription I already have with them) catches up with these new C# features I'll happily jump ship for new code and gradually shift over my old code.

  • Re: Time to take a look at F#

    by Isaac Abraham,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    And the fact that the article begins with "A common pain point in .NET programming" sadly shows just how awareness of F# is lacking. It should read "A common pain point in C# or VB .NET programming".

  • Looks like C# is slowly but surely morphing into F# with a C# syntax

    by Phylos Zero,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Just about every new feature added to C# has been in F# for years, if not since it's inception. Perhaps developers wanting advanced language features should just start using F# instead of getting these features in a piecemeal fashion with every new release of C#.

  • Explicitly defined backing store?

    by Craig Wagner,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Perhaps I'm just being dense here, but I don't understand why today each property requires an explicit backing store. For instance:



    public class Point
    {
    public int X { get; private set; }
    public int Y { get; private set; }
    public Point( int x, int y )
    {
    X = x;
    Y = y;
    }
    }


    Granted it's still more code than the example shown in the article, but this code does not declare explicit backing store variables yet once the object is created X and Y cannot be changed (other than using reflection of course). What am I missing?

  • Re: Explicitly defined backing store?

    by Jonathan Allen,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Semantically that means something different than a read-only field. But yes, as long as it is well documented that you intend those properties to never be touched it would serve the same goal.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT