In the section “Polymorphic ‘this’ type” of the Evolution Meeting 2020 blog post [Haxe Evolution meeting 2020 - Haxe - The Cross-platform Toolkit], examples are given where inheritance breaks certain method chains. Such as,
class Base {
public function doX():Base { ... return this; }
public function doY():Base { ... return this; }
}
class Child extends Base {
public function doZ():Child { ... return this; }
}
new Child()
.doZ()
.doX() // <- this method returns a Base, not a Child!
.doZ() // <- type error here: Base has no method doZ
.doZ();
I program a lot with such chains, but I have always felt like they are a bit of a hack for the sake of convenience and readability. A hack that may break and requires writing a non-negligible amount of boilerplate code.
Doing X, Y, or Z has no reason to output ‘this’, except for the chaining.
And, you might want to chain some actions that already have an output that isn’t ‘this’. For example,
class Stack {
public function pop():NotStack {...}
}
stack.pop().pop(); // Error. Pop does not return a Stack.
It seems that a proper solution would include some additional syntax at the calling site, to indicate that we want to chain operations on the same object. For example (with a few potential syntaxes),
stack~pop1()~pop2();
stack..pop1()..pop2();
stack->pop1()->pop2();
These are examples of a chaining syntax. stack is at the beginning of the chain, and pop2 is at the end of the chain. So, all method calls operate on stack, and the value of the chain is the return value of pop2.
This syntax addition would allow chaining to be used with any method without writing the ‘return this’ boilerplate. It would work with inheritance without a polymorphic ‘this’. And, it would make the intent of operating on the same object clearer.
I am not aware of any other language with this feature. I’m not sure why.
Maybe someone with more experience with programming languages and compilers has thoughts on this suggestion? The only downsides I can think of are adding more syntax to learn and needing to ensure the syntax does not conflict with existing syntax.