dead-claudia / lifted-pipeline-proposal

Proposal for lifted pipelines
35 stars 2 forks source link

Alternate operator choices #1

Open gabejohnson opened 7 years ago

gabejohnson commented 7 years ago

Opening an issue to track operator suggestions

gabejohnson commented 7 years ago

@isiahmeadows I know you're familiar w/ |> though it has slightly different semantics.

I also like ~> and <~.

Overloading >>> would let you have that and <<< (ala PureScript). This is probably not tenable.

dead-claudia commented 7 years ago

As for each of your suggestions:

dead-claudia commented 7 years ago

Another idea I just had was this: f :> g and g <: f (i.e. dropping the first-ish character).

JAForbes commented 7 years ago

I think we should stick with |> and <| unless there is a really good reason not to. Simply because that syntax has already been adopted by other languages. But if there is ambiguity, I like @isiahmeadows :> <: option too.

Great write up btw @isiahmeadows in the readme.

dead-claudia commented 7 years ago

@JAForbes Neither <:/:> nor <|/|> conflict with anything. I was just thinking that :> and <: are easier to type on a keyboard (you don't have to reach far to the right away from all the letters to type the operator).

charliesbot commented 7 years ago

What about <<, like Elm does? It feels easier to type.

gabejohnson commented 7 years ago

@charliesbox << is already taken. It's the bitwise shift operator.

charliesbot commented 7 years ago

oh bummer, you're right. I guess <<< like others said will do the trick :)

dead-claudia commented 7 years ago

Except the other direction >>> is also taken.

On Tue, Jul 11, 2017, 09:15 Charlie notifications@github.com wrote:

oh bummer, you're right. I guess <<< like others said will do the trick :)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/isiahmeadows/function-composition-proposal/issues/1#issuecomment-314439700, or mute the thread https://github.com/notifications/unsubscribe-auth/AERrBLpNOTW2GFSz7a0uHPUEh1VdSIzTks5sM3WBgaJpZM4Nuqwk .

tiansh commented 7 years ago

Just have a look on other languages:

Language Expression
Haskell f . g
SML f o g
F# f >> g, f << g
Perl 6 f ∘ g (∘ is U+2218)
Java 8 ((Function<T1, T2>)f).compose(g)
tiansh commented 7 years ago

Personally prefer a method instead of operator. Operator just making ES more and more complex.

Both are seems better than an operator to me.

charliesbot commented 7 years ago

considering that pipe is gonna be an operator for sure, I would say that composition should be an operator too just to be consistent.

My two cents.

https://github.com/gilbert/es-pipeline-operator

JAForbes commented 7 years ago

Yeah I agree, but I think the roll out of these things will be more successful if we stage it. That linked gitter thread covers my thoughts on this @charliesbox

dead-claudia commented 7 years ago

Plus, it's easier to optimize. There's a few complicating factors for transpilers specifically, though (requiring a bit more desugaring boilerplate), but it'd be nothing for engines:

Engines could do some seriously crazy stuff with it, though, even at the bytecode level:

The thing is, with a function instead, you have to wait for the JIT to kick in to detect the last one, and engines aren't likely to want to duplicate bytecode. This makes it much harder to derive any sort of special optimization, but by making it easily statically analyzable, there's fewer moving parts involved. In addition, transpilers could do the latter if it were syntax (offering most of the benefit up front), but not if it were just a function.

JAForbes commented 7 years ago

In addition, transpilers could do the latter if it were syntax (offering most of the benefit up front), but not if it were just a function.

I don't understand why that has to be true. Is there an assumption that someone might have changed the behaviour of the function so we can't special case Function.pipe when optimizing?

I guess I can understand that pessimism in the JS engine itself (even if I think its misguided). But with transpilers/build tools - that's a tool devs opt in to, and if you can identify that the native pipe function is being invoked, you could certainly inline many compositions.

And if this is the major reason for preferring syntax. Why can the proposal prevent reassignment (writeable=false), so we can guarantee expressions like Function.pipe are exactly what the JS engine thinks it is.

FWIW I think additionally having syntax could be a good thing (down the line). But could someone clarify this, because I keep hearing this argument about syntax being faster/easier to optimize and I don't understand it at all.

dead-claudia commented 7 years ago

@JAForbes

And if this is the major reason for preferring syntax.

Transpilers are more of an added bonus, but it would take a while as usual for implementors to get on board with anything they didn't themselves invent (like SharedArrayBuffer/Atomics), even with stuff they like.

Why can['t] the proposal prevent reassignment (writeable=false), so we can guarantee expressions like Function.pipe are exactly what the JS engine thinks it is.

It wouldn't exactly fit in with the rest of the spec that way, and that kind of thing would arise out of implementor feedback (why Symbol.iterator and friends are non-writable, non-configurable).

FWIW I think additionally having syntax could be a good thing (down the line). But could someone clarify this, because I keep hearing this argument about syntax being faster/easier to optimize and I don't understand it at all.

It really comes down to the fact if it's syntax, implementors could optimize statically with a few heuristics to ensure it's zero-cost and cheaper to create. If it were a function instead, you'd have to check if each argument is a lambda, and you could only do it when the JIT fires (so you couldn't avoid the overhead of an entire lambda).

When calling the composed function, it's much closer to identical, but here's the difference:

There's another benefit to just syntax: you don't have to cover the case of zero or one arguments, which the concept isn't well-defined in (at least mathematically). If you need to compose a list of functions, you could do it this way:

JAForbes commented 7 years ago

It wouldn't exactly fit in with the rest of the spec that way

The language spec do you mean? Yeah that's fair, but I think its worth considering very seriously because it solves a lot of problems and it doesn't "break the web"

It really comes down to the fact if it's syntax, implementors could optimize statically with a few heuristics to ensure it's zero-cost and cheaper to create. If it were a function instead, you'd have to check if each argument is a lambda, and you could only do it when the JIT fires (so you couldn't avoid the overhead of an entire lambda).

When you say lambda, do you mean arrow function? Is that so the compiler can identify the complete source of the function easily? Because I think the modules spec makes that a non issue, even for libraries. We should plan for what the language will be by the time this lands, as opposed to the confusing modules situation we have right now.

If we have a modules spec, then we can statically determine where a function came from and inline it no matter what its source is. Or at least attempt it in 99% of cases.

and you could only do it when the JIT fires

Does what I just said negate that? It should be 100% possible at parse time right?

When calling the composed function, it's much closer to identical, but here's the difference: Syntax: Call the composed function, mostly as if it were a normal function, and return the result. Function: Call the first function, and recursive pipe the result through the remaining functions for a > new result.

See I'm imaging both cases would be very different to that. Function.pipe (or syntax) could inline the entire composition into one function at parse time. Then when it executes, it's just executing 1 function. Whether its syntax or not right?

There's another benefit to just syntax: you don't have to cover the case of zero or one arguments

That's true, but that's sort of an edge case that I wouldn't want to use as a guiding principle for a spec design.

So with all that said, is there any advantage to syntax? Am I still misunderstanding something?

dead-claudia commented 7 years ago

@JAForbes

When you say lambda, do you mean arrow function? Is that so the compiler can identify the complete source of the function easily? Because I think the modules spec makes that a non issue, even for libraries. We should plan for what the language will be by the time this lands, as opposed to the confusing modules situation we have right now.

By "lambda", I mean any function expression. Also, engines could also broaden that to single-use functions, but that's a separate deal.

Does what I just said negate that? It should be 100% possible at parse time right?

See I'm imaging both cases would be very different to that. Function.pipe (or syntax) could inline the entire composition into one function at parse time. Then when it executes, it's just executing 1 function. Whether its syntax or not right?

Not necessarily, even if it's non-writable, non-configurable: what if the global Function is redefined before the script is executed, or conditionally overwritten at initial run time before the call? Engines compile before globals are known, and they create their ICs lazily to eventually speculatively optimize for the case everything is as you would expect.

Also, remember that the global object itself is a normal object with all its properties configurable, enumerable, and writable.

That's true, but that's sort of an edge case that I wouldn't want to use as a guiding principle for a spec design.

It makes things easier to explain to newbies.

So with all that said, is there any advantage to syntax? Am I still misunderstanding something?

There's also the aesthetic side, with fewer parentheses, but that's more of a style thing.

MiracleBlue commented 6 years ago

I'd personally like to put my 2¢ in and say that I am a huuuuge fan of PureScript's <<< and >>> syntax. To have that replicated in JS would just be brilliant as far as I'm concerned.

</¢2>

dead-claudia commented 6 years ago

@MiracleBlue >>> is out of the question as that's JS's unsigned logical shift right operator. (And obviously, functions can be coerced to integers that way.)

MiracleBlue commented 6 years ago

Damn :( that is unfortunate. I didn't realise it was already used for something in JavaScript. My apologies.

dead-claudia commented 6 years ago

@MiracleBlue To be fair, I would've liked >>/<<, except those are both taken.