Delegate operators through a trait so the delegating class supports $ and ?.
← Sealed Types and Traits · Ref: Q1133
'by' delegation forwards EVERY member of the trait that the class does not define itself - methods AND operators, '$' and '?' included:
PrinterWrapper with trait of Printable by delegate delegate as Printable?
Declare the operators on the trait, and the wrapper answers them through the delegate: '$wrapper' is the delegate's '$', 'wrapper?' is the delegate's '?', and a binary operator such as '+' is the delegate's '+'. The wrapper needs no 'operator ?' of its own, because the trait declares one.
A member the class declares itself is not forwarded: write 'override operator $' on the wrapper and its own '$' answers, while everything else is still forwarded.
Only members the TRAIT provides are forwarded: those it declares AND those it inherits from the traits it extends, but never what only Any supplies. If the trait provides no '$', the wrapper's '$' is its own (for example one 'default operator' generates from its fields).
The delegate is just another provider, so 'by' never resolves a conflict: if the super class, another delegated trait or a trait with a body also provides a member, the class must declare it (E06150 otherwise), and its body may call super or the delegate.
A trait operator that also exists on Any, such as '?', needs 'override' on the trait (E05120 otherwise).
See Q1129 for basic delegation. See Q1130 for chained delegation.
Example
#!ek9 defines module qa.sealedtraits.traitoperatordelegation defines trait Printable describe() as pure <- rtn as String: "default" operator $ as pure <- rtn as String: "trait-dollar" override operator ? as pure <- rtn as Boolean: true operator + as pure -> amount as Integer <- rtn as String: "trait-plus" defines class RealPrinter with trait of Printable model as String? default private RealPrinter() RealPrinter() -> initial as String model :=? initial override describe() as pure <- rtn as String: "RealPrinter" override operator $ as pure <- rtn as String: "real-dollar" //Set only when it has a model override operator ? as pure <- rtn as Boolean: model? override operator + as pure -> amount as Integer <- rtn as String: `real-plus-${amount}` //Forwards describe(), '$', '?' and '+' to the delegate - no operators of its own PrinterWrapper with trait of Printable by delegate delegate as Printable? default private PrinterWrapper() PrinterWrapper() -> printer as Printable delegate := printer //Declares its own '$', which wins; everything else is still forwarded LabelledWrapper with trait of Printable by delegate delegate as Printable? default private LabelledWrapper() LabelledWrapper() -> printer as Printable delegate := printer override operator $ as pure <- rtn as String: "labelled-dollar" defines program TraitOperatorDelegationDemo() stdout <- Stdout() wrapper <- PrinterWrapper(RealPrinter("laser")) //Delegated method call stdout.println(`describe: ${wrapper.describe()}`) //Delegated operators: each is answered by RealPrinter stdout.println(`dollar: ${wrapper}`) stdout.println(`isSet: ${wrapper?}`) stdout.println(`no model isSet: ${PrinterWrapper(RealPrinter(String()))?}`) stdout.println(`plus: ${wrapper + 3}`) //The wrapper's own '$' wins over the delegate's labelled <- LabelledWrapper(RealPrinter("inkjet")) stdout.println(`labelled dollar: ${labelled}`) stdout.println(`labelled describe: ${labelled.describe()}`)
Common mistakes
E05120 — '?' already exists on Any, which every trait extends, so declaring it on the trait overrides it and needs 'override'. '$' is not on Any, so it takes no 'override' on the trait.
Incorrect:
operator ? as pure <- rtn as Boolean: true
Correct:
override operator ? as pure <- rtn as Boolean: true
Other ways to ask this
- I need a wrapper class that delegates not just methods but also operators via a trait
- In Kotlin 'by' delegates interface methods. Show EK9 trait operator delegation
- Given a trait with operators, create a delegating class that forwards them
- Make a delegating wrapper support $ string and ? isSet through its delegate
Coming from another language?
Kotlin: class Wrapper(p: Printable): Printable by p - delegates the interface's members, and a member the class writes itself wins. EK9: 'with trait of X by field' - delegates the trait's methods and operators the same way, and a member the class declares itself wins.
Keywords: $, ?, by, delegation, forward, operator, trait