-
Notifications
You must be signed in to change notification settings - Fork 108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shorthand for pipe function definition? #131
Comments
pipe
function definition?
pipe
function definition?
Syntactic sugar is not "merely", it can be very important for clarity, lint-ability, expressiveness, teachability, etc. |
It's correct that it is not "merely" syntactic sugar, I suppose. I think for this case, there may be new cases for linting or expressiveness, this is true. However, I believe that you achieve some degree of expressiveness with having the function definition as well, the degree of difference in expressiveness is up to opinion. I believe that clarity gain depends on two parts: it's teachability (if it's not easy to teach then it's not clear to many), and the extent that the people that understand the feature can come back to their code later and read their code. I think that the teachability (relevant: #82) aspect suffers because this is not a familiar construct in most C-like languages and breaks C function call semantics (relevant: #132). I think that how easy it is to read, as opposed to the pipe function definition above, is marginal in difference, though there definitely is some difference that makes it easier to read for those that understand it. To summarize:
|
Teachability isn't solely/primarily about familiarity to other languages; the majority of JS developers in the future won't have ever touched another language before. |
Let's say that teachability is or is not a concern, up for debate, for the sake of argument. The question is now: I know that the purpose of this proposal is for the operator, but let's put that aside for a moment. I believe that (from a convenience sample in my workplace) introducing a new operator In fact, the front-end developers in my company, mixed of different types of framework developers from different backgrounds and different language preferences, preferred the function definition over the operator. They said that the The need for piping was clear. It provides a nice concise way of chaining function calls, among other things. They expressed, before the |
Doing anecdotal gathering of statistically insignificant data will favor whatever you want it to favor, depending on who you ask. I (and many developers I've talked to, not that that's a meaningful way to make design decisions) find syntax far more preferable to a function. |
My point isn't that my small, probably biased sample (as yours is as well), holds credibility to say a My point merely is to illustrate that if the The reasons they express are also reasons to consider. It might be easier to think about / adopt in the established JavaScript community because it is simply a function call instead of an entirely new syntax. Plus, polyfills for functions are viable, but polyfills for syntaxes are not. I ask you to simply consider that it might be a viable alternative for a minute. |
A |
Depends on the const pipe = (obj, ...funcs) => {
if (!funcs.length) return obj
const fn = funcs.shift()
return fn === pipe.await ? obj.then(_ => pipe(_, ...funcs)) : pipe(fn(obj), ...funcs)
}
pipe.await = Symbol('pipe/await')
const double = (n) => n * 2;
const increment = (n) => n + 1;
const veryExpensiveCalculation = (n) => Promise.resolve(n)
pipe(5,
veryExpensiveCalculation,
pipe.await,
double,
double,
increment,
double
).then(_ => console.log(_)) // 42 Realistically, though, a combination of const pipe = (obj, ...funcs) => funcs.reduce((o, f) => f(o), obj);
const compose = (...funcs) => (obj) => pipe(obj, ...funcs)
const double = (n) => n * 2;
const increment = (n) => n + 1;
const veryExpensiveCalculation = (n) => Promise.resolve(n)
// with pipe function
pipe(5, veryExpensiveCalculation)
.then(compose(double, double, increment, double)) |
@mAAdhaTTah It's actually something that this base proposal doesn't specify either and is an error in the scope of this proposal, as well. Of course, there's still the other proposals out there that have this await as well in their spec. |
I have been very eagerly waiting for this operator because this nonsense is such a frequent problem today (example use-case taken from the proposal description): boundScore(0, 100, add(7, double(person.score)))
// Or with useless helper variables that add no value
const doubled = double(person.score)
const adjusted = add(7, doubled)
const bound = boundScore(0, 100, adjusted) That's hard to read, cumbersome to write, and easy to get wrong. Maybe the partial application proposal would be sufficient to solve this problem on its own? pipe (
person.score
, double
, add(7, ?)
, boundScore(0, 100, ?)
) Looks good to me. |
@chrants The base proposal is unlikely to get accepted, as the committee has made it clear they want a pipeline that handles async / await. It functions as a strawman for comparing the tradeoffs between the other proposals. @noppa I wouldn't want to hitch the pipeline operator to partial application, but I'm of the opinion, if you get a pipeline operator, solving this with arrow functions is reasonable. |
Here is a more flexible const pipe = (obj, ...funcs) =>
funcs.slice(1).reduce((o, f) => (o.then) ? o.then(_ => f(_)) : f(o), funcs[0](obj))
const double = (n) => Promise.resolve().then(() => n * 2)
const doubleNow = (n) => n * 2
const increment = (n) => n + 1
pipe(5, doubleNow, doubleNow, increment, doubleNow) // returns 42
pipe(5, double, double, increment, double, console.log) // outputs 42 to console.log Some conceptual credit goes to sindresorhus / p-pipe, which does include error checking. I would personally favor this kind of a solution over adding yet another operator to the JavaScript language. |
Ignoring any subjectivity on syntax, the
|
Devil's advocate here (I still prefer the operator) - I think the OP and advocates here are suggesting a first-class Of course, then we get into the question of where to put/what to call such a function that wouldn't break the web, and it's definitely weird that a particular function would get special treatment by TypeScript/Flow and VMs. |
(microsoft/TypeScript#25826 (comment)) That point makes me wonder if adding this operator may have an impact on the relationship between JavaScript and TypeScript? |
In the end, I think that coming up with some concrete reasons why the pipeline operator should be used used over alternative approaches might help the operator gain even more traction, so I think that this discussion isn't bad for this family of proposals at all! If something seems to be more favorable, then great! Let's use that instead. Language authors knowing pros / cons of this particular approach can help decisively make it one way or another, and can help in explaining its particular utility to existing developers, as well. |
Closing this issue, as the proposal has advanced to stage 2 with Hack-style syntax, which brings additional benefits beyond just being syntax sugar for |
I believe the pipeline operator will bring only a small short-hand syntax for something that can be implemented with a simple function definition.
WORKING EXAMPLE MADE ON THE SPOT:
My question is does this merely bring some short-hand syntactic sugar for a set of functions that could be implemented in a few lines in current ES, or does it provide some substantial functionality besides that short-hand?
An alternative may be to add a set of equivalent functions with the functionality into the language. For example, a
pipe
function, as defined above, would probably suffice for most use-cases of the|>
operator.The text was updated successfully, but these errors were encountered: