7 people like it.

Phantom type example

The snippet shows a minimal example of phantom types for type-safe way of tracking different types of IDs in a simple system.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
// The idea is that you will have a generic wrapper ID<'T> and then use 
// different types for 'T to represent different types of IDs. Those types 
// are never actually instantiated, which is why they're called phantom types.

[<Struct>]
type ID<'T> = ID of System.Guid

type CustomerID = interface end
type ProductID = interface end

// Now you can create ID<CustomerID> and 
// ID<ProductID> values to represent two kinds of IDs:

let newCustomerID () : ID<CustomerID> = ID(System.Guid.NewGuid())
let newProductID () : ID<ProductID> = ID(System.Guid.NewGuid())

// The nice thing about this is that you can write functions that work with any ID easily:

let printID (ID g) = printfn "%s" (g.ToString())

// For example, I can now create one customer ID, one product ID and print 
// both, but I cannot do equality test on those IDs, because they're types do not match:

let ci = newCustomerID ()
let pi = newProductID ()
printID ci
printID pi
ci = pi 
Multiple items
type StructAttribute =
  inherit Attribute
  new : unit -> StructAttribute

Full name: Microsoft.FSharp.Core.StructAttribute

--------------------
new : unit -> StructAttribute
namespace System
Multiple items
type Guid =
  struct
    new : b:byte[] -> Guid + 4 overloads
    member CompareTo : value:obj -> int + 1 overload
    member Equals : o:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member ToByteArray : unit -> byte[]
    member ToString : unit -> string + 2 overloads
    static val Empty : Guid
    static member NewGuid : unit -> Guid
    static member Parse : input:string -> Guid
    static member ParseExact : input:string * format:string -> Guid
    ...
  end

Full name: System.Guid

--------------------
System.Guid()
System.Guid(b: byte []) : unit
System.Guid(g: string) : unit
System.Guid(a: int, b: int16, c: int16, d: byte []) : unit
System.Guid(a: uint32, b: uint16, c: uint16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit
System.Guid(a: int, b: int16, c: int16, d: byte, e: byte, f: byte, g: byte, h: byte, i: byte, j: byte, k: byte) : unit
type CustomerID

Full name: Script.CustomerID
type ProductID

Full name: Script.ProductID
val newCustomerID : unit -> 'a

Full name: Script.newCustomerID
System.Guid.NewGuid() : System.Guid
val newProductID : unit -> 'a

Full name: Script.newProductID
val printID : 'a -> 'b

Full name: Script.printID
val _arg1 : 'a
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val ci : obj

Full name: Script.ci
val pi : obj

Full name: Script.pi
Raw view Test code New version

More information

Link:http://fssnip.net/7Wn
Posted:5 years ago
Author:Tomas Petricek
Tags: types , phantom types