2

I want to define types that happen to be backed by the same type (say, FirstName and LastName, which are both strings), but I want them to be type-checked so that I cannot mix-and-match them by mistake:

> type FirstName = string;;
type FirstName = string

> type LastName = string;;
type LastName = string

> let n : FirstName = "John";;
val n : FirstName = "John"

//I wish this were caught:
> let l : LastName = n;;
val l : LastName = "John"

Is there a way to do this in F#, short of defining a record type or somesuch?

Larry OBrien
  • 8,484
  • 1
  • 41
  • 75

2 Answers2

4

You can use a single-case discriminated union:

type FirstName =
    | FirstName of string

type LastName =
    | LastName of string

let n = FirstName "John"
let l: LastName = n // error

More information on how these can be used can be found in a blog post here.

Mark Pattison
  • 2,964
  • 1
  • 22
  • 42
3

I believe Units of measure can be used on strings so you should be able to do this

[<Measure>]
type FirstName

[<Measure>]
type LastName

let n = "John"<Firstname>
let l:string<LastName> = n

and that will throw an error. Here is the MSDN Documentation of Units of Measure

theDarse
  • 749
  • 5
  • 13
  • In theory, it might be a good idea. Three years ago I asked [a related question](http://stackoverflow.com/questions/9417150/compile-time-constraints-for-strings-in-f-similar-to-units-of-measure-is-it) about how to manage those UoM, but the question still remains effectively unanswered. – Be Brave Be Like Ukraine Feb 12 '15 at 22:52
  • the thing about UoM's is they are a compiler feature in F# they are stripped from the compiled assembly. The above code will throw an error on compile, but in the assembly n and l are simply strings. So they can be accessed by any .Net assembly as strings, – theDarse Feb 13 '15 at 13:46