Skip to content

Instantly share code, notes, and snippets.

@eiriktsarpalis
Last active August 29, 2015 14:14
Show Gist options
  • Select an option

  • Save eiriktsarpalis/087775afe656ad31c311 to your computer and use it in GitHub Desktop.

Select an option

Save eiriktsarpalis/087775afe656ad31c311 to your computer and use it in GitHub Desktop.
NewType in F#
// current type abbreviations in F#
type A = Guid
type B = Guid
let foo (x : A) = x.ToString()
let b = B.NewGuid()
foo(b) // type checks
// proposed newtype abbreviations
newtype A = Guid
newtype B = Guid
let foo (x : A) = x.ToString()
let b = B.NewGuid()
foo(b) // type error
// newtype abbreviations should generate explicit conversion methods
let g : Guid = B.ToGuid b
let b : B = B.FromGuid g
// alternative attribute-based approach
[<NewType>]
type A = Guid
[<NewType>]
type B = Guid
@dsyme

dsyme commented Jan 23, 2015

Copy link
Copy Markdown
  • Where does the name "NewGuid" come from?

  • How would you declare an interface on the type? members? overrides such as ToString?

  • Do you want the type erased in .NET IL? If so, are you OK with the safety/reflection/... tradeoff here?

  • Also worth comparing with the proposed struct-on-record-or-unions

    [] type A = A of Guid

    or

    [] type A = { V: Guid }

    or even today (if you don't mind the copy-out of the GUID on access):

    [] type S(v:Guid) = member x.V = v

    The advantage of these is they don't require much new language machinery.

    BTW the performance testing results here don't apply to single-field structs because .NET optimizes those differently, they should be re-run for the single-field-struct case

@eiriktsarpalis

Copy link
Copy Markdown
Author

Good point. My original thinking was to avoid wrapping, but introduce a mechanism to statically distinguish between instances of the same underlying type much like how units of measure work. Admittedly, this is not as trivial as I originally thought.

@eiriktsarpalis

Copy link
Copy Markdown
Author

In response to your questions:

  • From the original type. But I'm wondering what type this method call should return: B or justGuid that would have to be converted explicitly? It gets even more confusing with instance methods. What would be the return type of FSharpMap.Add in case it got renamed? I think the same problem applies to using UoM over non-numerical values.
  • I think it should be impossible to declare overrides, excluding perhaps extension methods.
  • I think it should probably be erased. The reflection tradeoff is to be expected here.

@eiriktsarpalis

Copy link
Copy Markdown
Author

In other words, the struct approach is probably the better way of solving this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment