Consider the following code…
type TypeOne () =
member val Name = "" with get, set
type TypeTwo () =
member val Name = "" with get, set
member val Property = 0 with get, set
[<RequireQualifiedAccess>]
type UnionType =
| TypeOne of TypeOne
| TypeTwo of TypeTwo
// this only succeeds because we have defined the union type a
// requiring qualified access. otherwise TypeOne would be inferred
// as the union case, not the type (understandably)...
let t1 = TypeOne ()
// if we want t1 "as" the union type, we have to do the following...
let ut1 = UnionType.TypeOne t1
// the following function returns a result of type UnionType
// but we have to explicitly do this for each type
let makeUnion switch =
match switch with
| true -> UnionType.TypeOne (TypeOne ())
| _ -> UnionType.TypeTwo (TypeTwo ())
As in the comments, it seems like there’s no way of inferring that return results should be of a union type, and if we have to require qualified access on the union type this is extremely verbose (which seems worryingly wrong).
There’s also no way of creating a function that takes only the union types and returns them as the union. (In this case a function which takes a TypeOne or TypeTwo and returns UnionType). Or is there? Are there better ways of working with discriminated unions?
As pad has pointed out – you don’t need to qualify a union case with its parent type – so you can write
However you will always have to specify the
TypeOne. This is to avoid the ambiguity present if you have multiple cases which take the same arguments – likeThen even knowing the return type, the compiler can’t work out what to return. A more common example is actually with cases which take no arguments – say you decide to redifine true and false: