Skip to content

0.5.0 - Support for the decorator pattern / wrappers

Choose a tag to compare

@github-actions github-actions released this 07 Jun 20:29

With this release, it becomes possible to have the mutability of a decorator/wrapper depend on the mutability of the object it wraps. If you decorate a const object, the decorator is automatically const, and likewise for mut.
To make use of this, declare the member variable that holds the decorated/wrapped object as decorates:

interface NumberHolder {
    get fn n(self) -> U32
    set fn n(self: mut _, v: U32)
}

class SimpleNumberHolder : NumberHolder {
    private var _n: U32 = init
    override get fn n(self) = self._n
    override set fn n(self: mut _, v: U32) {
        set self._n = v
    }
}

class MultiplyBy4NumberHolder : NumberHolder {
    decorates private delegate: NumberHolder = init

    override get fn n(self) -> U32 {
        // here, self.delegate is a read NumberHolder, because the self reference is read, too
        return self.delegate.n * 4
    }
    override set fn n(self: mut _, v: U32) {
        if v.rem(4) != 0 {
            panic("must be a multiple of 4!")
        }
        // however, here self.delegate is mut because the decorator reference (self) is mut
        set self.delegate.n = v / 4
    }
}


fn example1() {
  var simple = SimpleNumberHolder(1)
  decorated: const MultiplyBy4NumberHolder(simple) // error: simple is mutable, the decorator is also mutable, not assignable to const
}

fn example2() {
  var mutDecorated: mut _ = MultiplyBy4NumberHolder(SimpleNumberHolder(1)) // works; exclusive nested object can be mut
  constDecorated: const _ = MultiplyBy4NumberHolder(SimpleNumberHolder(2)) // works, too: exclusive nested object can be const
}

This can not yet be combined with secondary constructors effectively, though.