On the topic of enforcing constraints for domain primitives (Constrained Primitive Values/Integrity of Primitive Values), you said to make the constructor private and add a create function.
So I looked at my domain and I have the following types of restricted strings:
type String2 = private String2 of string //2 chars max type ShortCode = String2 type String10 = private String15 of string type LongCode = String15 type String20 = private String20 of string type CategoryCode = String20 type String40 = private String40 of string type CategoryName = String40 type String45 = private String45 of string type Title = String45 type String255 = private String255 of string type BriefDescription = String255 type String1000 = private String1000 of string type LongDescription = String1000
note we talk in terms of codes; descriptions etc but I added the StringX alias for clarity.
Then, I thought I would be lazy/smart and make a reusable create function for this family of types. i.e, using generics:
let createRestrictedString<'T> friendlyName maxLength str = if String.length str > maxLength then Error (friendlyName+" must not be longer than "+maxLength.ToString()+" characters") else Ok( typeof<'T>.GetConstructor(System.Reflection.BindingFlags.Instance ||| System.Reflection.BindingFlags.NonPublic, null, [|typeof<string>|],null).Invoke [| str |] :?> 'T)
and now we get simple useage:
let createShortCode = createRestrictedString<ShortCode> "ShortCode" 2
let x = createShortCode "ab" let y = createShortCode "cde"
[<Struct>] val x : Result<ShortCode,string> = Ok String2 "ab" [<Struct>] val y : Result<ShortCode,string> = Error "ShortCode must not be longer than 2 characters"
However this solution probably incurs some runtime cost due to reflection - is there a more elegant or performant solution using quotations perhaps?
Thank you, f# newbie here!