Sylverblack
Sylverblack

Reputation: 13

Mutable internal value in discriminated union

The task is to create a binary tree with its nodes having a member is_locked that can be true or false and a method lock() that shall set is_locked to true if it's not already.

I tried this

type BinaryTreeNode =
    | Node of BinaryTreeNode * BinaryTreeNode
    | End
    with
        let mutable internalIsLocked = false
        member this.is_locked
            with get() = internalIsLocked 
        member this.lock() = internalIsLocked <- true

but compiler says no due to This declaration element is not permitted in an augmentation at the let binding.

val mutable internalIsLocked : bool instead does not work for the same reason.

How can this problem be solved then? Is it not solvable with discriminated unions?

Upvotes: 1

Views: 143

Answers (1)

Brian Berns
Brian Berns

Reputation: 17038

If you really want to do this, you can move the mutable state into a separate class type, and then use that type in your discriminated union:

type Lock() =
    let mutable internalIsLocked = false
    member this.is_locked
        with get() = internalIsLocked 
    member this.lock() = internalIsLocked <- true

type BinaryTreeNode =
    | Node of Lock * BinaryTreeNode * BinaryTreeNode
    | End
    with
    static member Create(left, right) =
        Node (Lock(), left, right)
    member this.Lock =
        match this with
            | Node (lock, _, _) -> Some lock
            | End -> None

Note that I've assumed that End nodes are not lockable. Usage:

let node = BinaryTreeNode.Create(End, End)
node.Lock.Value.is_locked |> printfn "%A"   // false
node.Lock.Value.lock()
node.Lock.Value.is_locked |> printfn "%A"   // true

However, I wouldn't recommend it.

Upvotes: 1

Related Questions