How do I Override ToString in a Composite Type in F#?

2.7k views Asked by At

I'm learning about creating composite* types in F# and I ran into a problem. I have this type and a ToString override.

type MyType =
    | Bool of bool
    | Int of int
    | Str of string
    with override this.ToString() =
            match this with
            | Bool -> if this then "I'm True" else "I'm False"
            | Int -> base.ToString()
            | Str -> this

let c = Bool(false)
printfn "%A" c

I get an error inside the ToString override that says "This constructor is applied to 0 argument(s) but expects 1". I was pretty sure this code wouldn't compile, but it shows what I'm trying to do. When I comment out the override and run the code, c is printed out as "val c : MyType = Bool false". When I step into that code, I see that c has a property Item set to the boolean false. I can't seem to access this property in the code however. Not even if I annotate c.

How should I be overriding ToString in this situation?

* I'm pretty sure these are called composite types.

1

There are 1 answers

0
N_A On BEST ANSWER

When you are using a Discriminated Union (DU) (that's the appropriate name for that type), you need to unpack the value in the match statement like this:

type MyType =
    | Bool of bool
    | Int of int
    | Str of string
    with override this.ToString() =
            match this with
            | Bool(b) -> if b then "I'm True" else "I'm False"
            | Int(i) -> i.ToString()
            | Str(s) -> s

let c = Bool(false)
printfn "%A" c

The Item property that you're seeing is an implementation detail and is not intended to be accessed from F# code. Merely using this doesn't work because the DU is a wrapper around the value, so this refers to the wrapper, not to the contained value.