Today’s random F# code: Domain modelling with discriminated unions

F# makes it easy to model a domain with discriminated unions (= it is one of these values) and measures (type-safe numbers). Excerpt from our expenses sub-system:

* in a type definition stands for a tuple: int * string is a tuple of an int and a string, like 42, "this is a tuple". The definition uses a *, the values a ,.

Single-case discriminated unions like type DimensionId = DimensionId of Guid are a simple way of making basic types type-safe. There is an alternative: using FSharp.UMX allows using measures on GUIDs (I’ll post an example later).

Normal discriminated unions are great for expressing that a value is either this or that:

type MyDiscriminatedUnion =
    | This
    | That of MyData: string

And you can add data to the cases.

And, of course, all these types are immutable and support structural comparison out of the box.

About the author

Urs Enzler

2 comments

  • We have tons tutorials about domain modelling with DUs which are pretty much copies of the Scott Wlaschin’s blog post. And as with the original blog post there’s a huge problem when using DUs and records for modelling: all fine and dandy until you have to access the actual value or update an entity – and then you drown in so much line noise that Java dies from envy.

  • Your experience doesn’t match my experience.
    – Accessing values of a record is the same as in most other languages
    – accessing a union case with a match expression isn’t what I would call boilerplate code
    – updating values in a record with the { value with FOO = 42 } syntax is very convenient and preserves immutability.
    – when one has to frequently update fields, then go with a mutable type and it’s the same as in all C-style languages

By Urs Enzler

Recent Posts