This could be a long-shot but…
I have some code, below, which I have stripped down from the real code. (Apologies for the length but at least it can be evaluated in the FSI.)
I am reading some records from a database, converting them into Domain records, doing some modifications, and then saving them back to the database, but that’s probably not important.
When a MyThing
value is of type SingleDigit
, only the AllowZero
value is valid.
When a MyThing
value is of type MultiDigit
, only the NumberOfDigits
and Suffix
values are valid.
In the code this works as expected but, I would like to be able to keep the AllowZero
value and the Suffix
value ‘behind the scenes’ when switching between the two in changeNumberOfDigits
, so the previous values can be restored when the type changes rather than hard-coding some defaults, which isn’t currently possible with this design.
Basically, when the user reduces the number of digits to one I want to somehow keep the previous value of Suffix
so it can be reinstated if the number of digits goes higher than one again. Same sort of thing for AllowZero
but the other way round.
I did another version where I kept these fields in each type of MyThing, e.g.:
type SingleDigit = { AllowZero : bool ; Suffix : string option }
type MultiDigit = { NumberOfDigits : int ; Suffix : string option ; AllowZero : bool }
…and just ignored them when they weren’t needed, but I was wondering if there was a better way.
I thought about storing the ‘missing’ values in other fields with different names (e.g. AllowZeroBackup in MultiDigit) but that’s not much better and could be even more confusing.
Every change will result in a database overwrite of the original record so using that as a ‘backup’ isn’t an option.
Holding the ‘missing’ values in another separate record would probably not be a good idea either, and it would certainly make things more complicated.
This code is only being, and will only be, used by me personally so as long as I document things nicely there probably won’t be a problem with the field duplication version but I would like to know if there is a better way in case I need it later.
And here’s the code:
open System
type SingleDigit = { AllowZero : bool }
type MultiDigit = { NumberOfDigits : int ; Suffix : string option }
type MyThing =
| Single of SingleDigit
| Multi of MultiDigit
let changeNumberOfDigits number pattern =
match pattern, number with
| Single _, 1 -> pattern
| Single _, _ -> Multi { NumberOfDigits = number ; Suffix = Some "hello" }
| Multi _, 1 -> Single { AllowZero = false }
| Multi existing, _ -> Multi { existing with NumberOfDigits = number }
let toggleAllowZero pattern =
match pattern with
| Single { AllowZero = allowZero } -> Single { AllowZero = not <| allowZero }
| Multi m -> Multi m
let changeSuffix newSuffix pattern =
match pattern with
| Single s -> Single s
| Multi m -> Multi { m with Suffix = newSuffix }
let printValue =
let ofCharArray (chars : char array) = System.String(chars)
fun pattern ->
do
match pattern with
| Single {AllowZero = allowZero} when allowZero = true ->
printfn "0"
| Single _ ->
printfn "5"
| Multi { NumberOfDigits = numberOfDigits ; Suffix = suffix } ->
let number =
'9'
|> Array.replicate numberOfDigits
|> ofCharArray
suffix
|> Option.defaultValue String.Empty
|> (+) number
|> printfn "%s"
pattern
Single { AllowZero = true }
|> printValue
|> changeNumberOfDigits 4 // AllowZero value is lost here.
|> printValue
|> changeSuffix (Some "changed")
|> printValue
|> changeNumberOfDigits 1 // Suffix is lost here.
|> printValue
|> toggleAllowZero
|> printValue
|> changeNumberOfDigits 6 // AllowZero value is lost here again.
|> printValue
|> changeNumberOfDigits 1 // Suffix is lost here again.
|> printValue