Fwd: Function composition syntax

Isiah Meadows isiahmeadows at gmail.com
Wed Sep 28 23:20:10 UTC 2016


Somehow, this missed the list...

---------- Forwarded message ---------
From: Isiah Meadows <impinball at gmail.com>
Date: Wed, Sep 7, 2016, 12:03
Subject: Re: Function composition syntax
To: <mikesamuel at gmail.com>, <es-discuss at mozilla.org>


I was thinking in reverse order, but personally, I'm flexible on specifics
like that.

On Wed, Sep 7, 2016, 12:00 Isiah Meadows <isiahmeadows at gmail.com> wrote:

> Inline.
>
> On Wed, Sep 7, 2016, 11:05 Mike Samuel <mikesamuel at gmail.com> wrote:
>
>> On Wed, Sep 7, 2016 at 10:10 AM, Isiah Meadows <isiahmeadows at gmail.com>
>> wrote:
>> > I would like to see a function composition operator make it into the
>> > language. Currently, there is:
>> >
>> > - Lodash: `_.flow` and `_.flowRight` (lodash/fp alias: `_.compose` and
>> > `_.composeRight`)
>> > - Underscore: `_.compose`
>> > - Ramda: `R.compose`
>> > - Tons of npm modules:
>> https://www.npmjs.com/search?q=function+composition
>> > - Numerous manual implementations
>> >
>> > Function composition could be far more efficiently implemented in the
>> > engine, in ways not possible at the language level:
>> >
>> > 1. They can create pipelines to optimize multiple composition chains
>> > together.
>> > 2. They can avoid most of the closure allocation cost internally.
>> > 3. The returned functions can internally use a separate call path to
>> avoid
>> > some of the [[Call]] boilerplate when called and when calling the
>> functions
>> > themselves (you don't need to verify twice).
>> >
>> > Here's what I propose: a new infix operator `>=>` (operator and
>> direction
>> > can change) for composing two functions. It would do the following:
>>
>> What is the advantage of an operator over a static `Function.compose`
>> or `Function.compose{Left,Right}`?
>>
>
> See my section on why I suggested the operator instead of a function. One
> of the biggies is that the engine can statically optimize it, including
> inline arrow functions (no function object needs created). Another that I
> didn't list is that you are guaranteed 2 operands, so you can't "compose" 1
> function. Also, fewer parentheses are always better IMO.
>
> Oh, and there's a reason most `compose` functions accept multiple
> arguments: it would become way too unwieldy with all the parentheses
> otherwise.
>
>
>> > 1. Verify both operands are callable.
>>
>> What should happen if you try to compose something that only supports
>> [[Call]] with something that only supports [[Construct]]?  For
>> example, one might try to compose Object.freeze with a constructor to
>> get a producer of frozen instances.
>>
>
> I can adjust my proposal accordingly to cover "construct first when called
> as constructor". I missed that use case, but it's easy to fix.
>
>
>> > 2. Create a callable-only function that calls its left operand with the
>> > original arguments and `this`, then calling its right operand with the
>> > result and the same `this`.
>>
>> > 3. Sets its length to the left operand.
>> > 4. Return the new function.
>>
>> Is the new function strict only when both operands are strict or when
>> either is strict?
>> Or should it depend on the scope in which the operator appears?
>>
>> When the left operand is non-strict, is the composition the caller of
>> the left operand?
>>
>
> Composed functions would be similar to bound functions. So it shouldn't
> make a difference.
>
> A transpiler can transform `f >=> g` directly to `function () { return
> g.call(this, f.apply(this, arguments)) }` (mod type checks).
>
>
>> > The reason I suggested an operator instead of a function:
>> >
>> > 1. Fewer parentheses is always a plus.
>> > 2. It allows engines to statically optimize functions in the middle
>> (avoid
>> > an extra function allocation), like with `f >=> x => console.log("x:" +
>> x)`.
>>
>> This seems doable optimistically with Function.compose, though you'd
>> have to back out when Function.compose is assigned.
>>
>
> Engines don't usually make optimistic assumptions like that on the first
> pass, much less the first 100 or so (it takes thousands for V8's inliner to
> trigger, for example). They would have to cut a very specific special case
> for this (they don't even do that for `bind` IIRC), which I don't see as
> likely.
>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160928/4e04291f/attachment.html>


More information about the es-discuss mailing list