Syntax to get same object that method was called on (Easy method chaining)

Bob Myers rtm at gol.com
Mon Oct 26 17:05:34 UTC 2015


I love cool syntactic innovations as much as the next guy. I'm sure there
are a bunch sitting out there waiting to be discovered that will make us
all sit back in awe.

But it's not a particularly new insight to observe that especially if they
introduce no new basic functionality and are just sugar, then such
innovations have to solve a real pain point, not have simple user-side
solutions, and not eat too much into the syntactic space for better future
ideas.

Here, I'm really having a hard time trying to figure out what's so painful
about

    obj.foo();
    obj.bar();

that would lead us to introduce `.{` or `..` or `#.` to solve the problem
of typing `obj` twice. The resulting code (whether `obj.foo()..bar()` or
`obj.{foo(); bar()}` or `obj.foo()#.bar()`) is neither more writable, nor
more readable, nor more maintainable, nor more provably correct. On the
contrary. All are more obtuse, obscure, and bug-prone.

As a semi-ridiculous example of a seemingly useful new syntactic structure,
let me introduce the `<#>` syntax. This is a mechanism for writing an
expression, enclosed in `<>`, which throws away its value and instead
evaluates to a value within the expression prefixed by a (tightly-bound)
`#` operator. So, for instance, I can write

    return <foo(#5)>;

In other words, call `foo(5)`, but deem the expression to evaluate to 5 and
return that.

The proposed `obj.foo()#.bar()` could be written as

    <#obj.foo()>.bar();

I have no trouble imagining that this syntax could result in some more
compact code, but I doubt if it would be more writable or readable. It's
syntactic over-think.

Another criteria for accepting new syntax ideas is that they should be
general and compositional. In other words, they should solve more than one
problem. Solving the single problem of "take a method call on an object and
fix it up so that later stuff in the expression refers to the object
instead of the result of the method call" does not meet this criteria.

I mean, if you want to write chainable functions, then just write them that
way.

If you have non-chainable functions, and you want to make them
chainable/cascadable, it's not a real problem to chainify a function:

    function chainify(fn) {
      return function() {
        void fn.apply(this, arguments);
        return this;
      };
    }

    obj.doSomethingChained = chainify(obj.doSomething);
    obj.doSomethingChained().doSomething2();

If you have a whole set of APIs you want to chainify, you could take a leaf
from the `promisifyAll` paradigm, and do it all at once:

    chainifyAll(obj);

which would create methods xxxChained for all methods on the object.

--
Bob
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20151026/7547747f/attachment.html>


More information about the es-discuss mailing list