Last active
August 29, 2015 14:14
-
-
Save eiriktsarpalis/087775afe656ad31c311 to your computer and use it in GitHub Desktop.
NewType in F#
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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 |
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.
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 ofFSharpMap.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.
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
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