

Chainvas: a tiny library that can add chaining to any API like Canvas and DOM - aycangulez
http://leaverou.github.com/chainvas/

======
raganwald
I applaud people for trying to find clean ways to add chaining to langauges
like JS, but feel we are working at the wrong level of abstraction. Chaining
is a syntax and grammer problem, not a semantic problem. Smalltalk solved this
by making chaining part of the syntax. if you write:

    
    
      foo
        :bar;
        :bash something;
        :thenBlitz.
    

The semi-colons tell the interpreter to chain the method calls to the original
receiver. That way you can read the sntax and know chaining is involved
without needing to know whether those methods were written to be chained. The
return value of a method is its _semantics_ , and should not be chosen to try
to implement syntax.

Summary: This problem should be solved by the parser, not by the function
author.

p.s. paging @jashkenas!

p.p.s. Did you ever take that test yourself? Yes, my comments apply doubly to
libraries like #andand.

~~~
jashkenas
Reporting for duty...

A dedicated syntax for chaining has been discussed several times for
CoffeeScript, with different flavors:

<https://github.com/jashkenas/coffee-script/issues/1495>

<https://github.com/jashkenas/coffee-script/issues/1291>

<https://github.com/jashkenas/coffee-script/issues/281>

<https://github.com/jashkenas/coffee-script/issues/1431>

Personally, I'm a bit iffy on the subject, because although the demonstrated
usefulness of the idiom is evident in libraries like jQuery, chaining-as-a-
language-feature is inherently focused on stringing together a sequence of
imperative side effects, where it can be nicer to use expressions for their
values.

For example, where the returned value is a part of the next step of the
computation, chaining comes naturally:

    
    
        list
          .concat(other)
          .map((x) -> x * x)
          .filter((x) -> x % 2 is 0)
          .reverse()
    

And where you need built-in language chaining to do the job for you, it's
almost always because you're ignoring the return value, and using each method
for its side effects:

    
    
        brush
          .startPath()
          .moveTo(10, 10)
          .stroke("red")
          .fill("blue")
          .ellipse(50, 50)
          .endPath()
    

So the enforced imperativeness of chaining syntax makes it feel a bit off.
Still, if you were designing such a syntax from scratch, and not following
Smalltalk's lead, what would you think it should look like?

~~~
raganwald
I would use indentation to discriminate between the cases:

    
    
        list
          .concat(other)
            .map((x) -> x * x)
              .filter((x) -> x % 2 is 0)
                .reverse()
    

For pipelining, and:

    
    
        brush
          .startPath()
          .moveTo(10, 10)
          .stroke("red")
          .fill("blue")
          .ellipse(50, 50)
          .endPath()
    

For what we are calling “chaining.” I use this now as a personal coding style
when writing jQuery stuff with JQuery Combinators:

    
    
      added
        .addClass('atari last_liberty_is_' + ids_of_added_liberties[0])
        .find('#'+ids_of_added_liberties[0])
          .when(doesnt_have_liberties)
            .removeClass('playable_'+added_colour)
            .addClass('no_liberties’);
    

The first “addClass” and “find” are both sent to “added,” “when” is sent to
the result of “find”, “removeClass” and the second “addClass” are both sent to
the result of “when.” It feels to me very much like how we indent scope and
syntactic blocks like “if” or “unless."

~~~
jussir
Looks very nice! Though the discrimination between intending or not is done
based on whether the previous action mutates the object (no new intend) or
creates or returns different object (new intend), right? This is something
that can't be known on the language level unless there's a specific syntax for
it, which doesn't seem to be possible for Javascript based languages (e.g.
<https://github.com/jashkenas/coffee-script/issues/1738>).

~~~
raganwald
My point is that if I owned the parser, I would ignore what the function
returns and send the message to the previous receiver when multiple message
inocations are indented in parallel. Here's an example using functions that
both return a value and have a side-effect:

    
    
        ['foo', ['bar']]
          .pop()
          .pop()
    

Would return 'foo' if I owned the parser, while:

    
    
        ['foo', ['bar']]
          .pop()
            .pop()
       

...would return 'bar'. You can infer from his what happens to the niial array
in terms of side effects. My suggestion is that "chaining" method calls is a
syntax issue and not a function issue, and that writing functions tonreturn a
certain thing just to cater to how you like to write programs is hacking
around a missing language feature.

pop() is a great example. Why shouldn't pop return the receiver? The first
example makes sense, you ought to be able to chain calls to pop(). Then again,
why shouldn't pop() return what it pops? You ought to be able to pop something
and use it, just like the second example.

Baking chaining into what functions return forces the function author to
choose On behalf of the function user. I do not blame people for doing this in
a language lacking thenproper syntax, but given how much people do this, it
seems worth considering for people writing new langauges or new syntaxes for
existing languages.

------
duncanbeevers
Reminds me of node-chainsaw: <https://github.com/substack/node-chainsaw>

Also, my own node-ContextChain <https://github.com/duncanbeevers/node-
ContextChain>

Both of these libraries take the approach of wrapping the underlying object
rather than modifying it.

------
richbradshaw
This website (much like all of Lea's work) has loads of really nice details –
worth reading through the source code for anyone who works with CSS.
Particularly the use of border-image, though there are a number of other nice
little things going on here!

------
wavephorm
I've always thought the chaining methods thing that jQuery popularized was a
pristine example of an anti-pattern. It might save a few keystrokes, but I
question whether anyone really writes code like this the first time through. I
suspect people actually take perfectly fine working code and refactoring it
into a chain just to make the code appear more clever, all the while making
the code harder to read and debug.

~~~
tikhonj
I like chaining because it emphasizes that a set of method calls is part of
one discrete action involving one object.

For example, take adding a header to some text: it's one action, but it
involves multiple steps. First I create the actual element, then I give it a
class name, add some text and finally insert it in the DOM. I think chaining
not only makes the code easier to read (and type, although that isn't
particularly important), but also makes its semantics clearer.

~~~
wavephorm
That's what functions are for. Chainable methods don't make multiple step
operations more concise.

