Open EdSaleh opened 3 years ago
This is a syntax shorthand for IIFEs, correct? This kind of idea has been proposed a handful of times, and while it solves many of the same problems that the current proposal solves, it doesn't solve them all. You can find conversations related to this kind of idea here and here.
Additionally, I'm not sure this specific idea is as simple as you think it is. For example, you still have to figure out what to do about edge cases, like if-without-else, etc, just like the current proposal. You also linked the "implicit return" issue here, saying this was a solution to that problem. I'm not sure I see how. All of the issues with implicit returns are also an issue with this syntax.
const result = do {
f()
g() // Confusingly, g() is being implicitly returned.
}
const result = do if (true) {
let x = y
[2] // asi hazard, will get interpreted as y[2]
}
The main pushback I've seen for not wanting simply an iife shorthand, is the fact that iifes don't support using await, break/continue, return, etc against its parent function - those keywords would only apply to the iife.
Finally, a good thing to keep in mind, is that the pattern-matching proposal is planning on utilizing the do blocks for their blocks. It'll look something like this:
const result = match({ x: 2, w: 4 }) {
when ({ w, x: 2 }) { // This is a do block, not a normal block
let y = 3
w + y
}
}
console.log(result) // 7
We need to make sure we provide some user-friendly solution for pattern matching constructs to be able to execute a block of code in an expression position.
I too think the do block proposal in its current state is pretty complicated, and I'm all for trying to find ways to simplify it down. I've tried to propose an IIFE shorthand myself at one point, and received some of this information as feedback.
Hi Scot,
Thank you for your reply. My proposal doesn't need to worry about implicit return. I'm very against it that I had my proposal for rust lint approved to add a role that allows disabling it.
My proposal is just a syntax suger for executed anonymous function (()=>{*function body*})()
. So instead of that form, we just do => {*function body*}
or {value} => {*function body with value object fields*}
or do {*function body*}
to achieve the same thing. It's not a new statement, just a syntax suger with a regular function.
Thank you
Implicit return if it would come to JavaScript, should be generally added to all functions in JavaScript, not just one statement. Using regular functions to implement do expression
would allow us to not worry about implementing implicit return now.
It already exists in JavaScript, in concise arrow bodies, and also in eval.
Functions can’t be used for do expressions because they need to be able to control the surrounding function with return/await/yield.
I think my proposal could be used for both do statement and match statement, using the form with a parameter {value}=>{*if/switch(value.)...}
Hi Jordan,
Thank you for reply.
My method is able to get the sorounding state block since it's an arrow function, but it won't be able to use return
or yeild
of sorounding state block.
Thank you
Yes, it it's possible to do my method in JavaScript now, but I'm proposing a shortcut.
You can always return a state from my proposed method that would allow controling yeild/return of outer state function though.
Sorry - I didn't look close enough, you're right that you were using the return
keyword and not doing implicit return, so yes, you don't have any issues there.
You can always return a state from my proposed method that would allow controlling yeild/return of outer state function though.
This can be cumbersome to do though. Compare the following:
// Current proposal
const result = do {
const condition = ....
if (condition) await f()
g()
}
// To achieve a similar behavior in your proposal
const result = await do {
const condition = ....
if (condition) return f()
return g()
}
// Note that we're needlessly awaiting g() as well.
// To achieve the same effect as the original proposal while
// not awaiting syncrounous values, we would have to do this:
let stuff = do {
const condition = ....
if (condition) return { promise: f() }
return { result: g() }
}
const result = stuff.promise ? await stuff.promise : stuff.result
It's suspected that this will be a common issue, which is why people are a little wary of this sort of solution. Especially with returning from a function - trying to pipe a return value all the way down through multiple layers of match(), and doing this sort of unpacking could be very cumbersome.
I think my proposal could be used for both do statement and match statement, using the form with a parameter {value}=>{*if/switch(value.)...}
I'm not sure I fully understand your parameterized form. Is that just a shorthand for declaring local variables inside your iffe syntax?
@EdSaleh its a requirement of some delegates to be able to await or yield a surrounding async/generator function, so if that’s not allowed by your proposal, then it’s a nonstarter.
Alternatively, if you don't make it an iife shorthand, then you could have async/return/yield/etc within your shorthand syntax. You'll end up something very similar to this discussion #1.
That, together with requiring an explicit completion value marker (like discussed in #72) should give us something that's about as simple and intuitive as what you're proposing here.
Thank you very much for replies.
The parameters work by mapping the single object fields value of my proposed method to its inner states. It allows only a one single object as a parameter.
Example:
const a=1,b=2;
const c =
{a,b}=> {
if(a) return a;
else if(b) return b;
else return 0;
}
console.log(c)
It's a simple, easy and less verbose shortcut.
If you decide to plan the statement block route for do rather than function block. You can use new keywords like break
or new retrieve
or done
to exit and return from do
block. Implicit return should a property of a whole programming language not one single statement of a programming language.
Thank you
I'm personally glad this proposal is alive again and discussing, but I think the main question should be if rethinking it now is simply gonna delay actual implementation (I think it's been stuck the longest I've personally experienced). Node by Chromium had it built in under a harmony flag, that is taken out. Babel is not moving it to basic packages, while moving far newer proposals up.
I love do expressions more than anything for some reason and it's the first thing I'll make sure is added in new repos whatever way possible. I followed all my node calls with a --harmony-do-expressions (at least till recently, now it 's taken out and quits node), install @babel/plugin-do-expressions and download Typescript pull request with do expressions. To be honest I only think Typescript has a chance of brining this in a "I can justify using it for production", as currently proposed, in a somewhat soonish fashion, let's not see what's gonna happen if we change the proposal up now.
What can we do to "push" for this proposal? I already force everyone that wants to read my code to learn about them, most start using them themselves and are intrigued. Don't really understand what's the holdup on the proposal. It was already in Node done by the Chromium v8 team two years ago...
install @babel/plugin-do-expressions and download Typescript pull request with do expressions
Hi happy to see someone is really using that TS PR, but I want to notice you, babel plugin is implementing the older version of this proposal (doesn't support return, break and continue) and the TS version is missing some pieces (switch, etc).
Pipe and Chaining Example: Consecutive chains inherit the single parameter of single field object of parent chain, each assigning return value to that single field object property and passing that as parameters to next chain
const value=1;
const c = {value}
=> value+1
=> value+1
=> value+2
console.log(c) //5
The difference between {x} => x
and ({ x }) => x
is far, far too subtle, so this syntax is also a nonstarter.
We can of course discuss the syntax, my proposal has 3 suggestions: =>
, ->
, do
. The reason I prefer =>
is because my method is actually based on anonymous method, just immediately executed, and allowing flexibility.
Alternative Syntax:
const c = value
-> value+1
-> value+1
-> value+2
console.log(c) //5
As I indicated here, the entire concept is a nonstarter - a proposal based on function boundaries will not achieve consensus.
Given that, the specific syntax isn't particularly important.
Of course this proposal is open for any modifications and subjective discussion in regard to consensus. Thank you
imo the modifications required would result in the current proposal.
Yes, I like the ideas of the current proposal, except for the implicit return and that could be improved with creating a new keyword to break or exit or retrieve from do block. The reason I made this proposal is because it's simpler than current one, and would also allow matching, and piping.
Matching and piping are separate proposals, and "would also allow" doesn't sound like "simpler" to me. The current proposal is simple.
Implicit return is likely inevitable, given that there does not exist any convention for any kind of interrupting flow control to provide a value besides yield
or return
or throw
(none of which are options here), and nobody has yet come up with a keyword that would suffice. Either way, that can be discussed in #72.
Ok, thank you.
I'm not sure I understand your pipe syntax.
const c = value
-> value+1
-> value+1
-> value+2
console.log(c) //5
This is pretty odd. From what it looks like, you can only put an identifier in the left-most position, and then each state of your "->" pipe will cause the value in your identifier to be modified? i.e. if I logged the value of "value" after I executed this, would it be 4 more than what it used to be? Normally, a pipeline operators would try not to modify anything - you can see the current proposal for the pipeline operator here. One variant would look something like this:
const c = value
|> ^ + 1
|> ^ + 1
|> ^ + 2
console.log(c)
The "^" symbol is a topic variable, that holds the value of the result of the previous pipeline's completion value. It can, of course, take your "->" syntax inside the pipeline if you need a statement as an operand.
const result = y.z
|> -> if (^) return 1; return 2;
|> ^ + 1
Each preceding item statement in chain acts as the parameter value for the next item statement in chain. So first item in the chain gets value parameter, then the next item in the chain gets the return from the previous item, but under the name 'value' as well. It's as if each item in the chain has a parameter 'value', equaling the return of the previous item in the chain.
this
const c = value
-> value+1
-> value+1
-> value+2
console.log(c) //5
equals:
const value1 = value;
const value2 = value1 -> value1+1
const value3 = value2 -> value2+1
....
console.log(c) //5
So, would this not be allowed?
const c = obj.value
-> ???? + 1 // What goes in the ????
No it's not allowed since you need an object to be mapped to the immediately executable arrows function.
{value: obj.value}->value+1
Or
({value: obj.value})->value+1
Or
{obj}->obj.value+1
Or
obj->obj.value+1
Or
{obj}=>obj.value+1
We can rename the proposal to Immediately Executable Arrow Function(s) or Immediately Invoked Arrow Function(s) or Immediately Invokable Arrow Function(s) since you can have multiple chain of functions in the same statement chain.
I once assumed a syntax using ->
a->f() // f(a) f is ident
a->f(b) // f(a, b)
a->[f](b) // f(a, b) f is expr
foo
->bar()
->baz()
// baz(bar(foo))
foo->bar {
// with tail block
}
// bar(foo, () => {})
as a substitute for pipelines, it can be used directly in existing functions
I am worried about operator ->
being occupied
Maybe we can use like
const a = do () => 1
Hi 2A5F,
That's actually good syntax, maybe start chain with do ()=> {}
and use =>
for consecutive chain items do ()=> {} => {} ...
Thank you
Syntax '|> {}' could be used as well.
Introduction
Hello,
I had an idea to allow returns from statements and decided to do a research and found Do Expression proposal very similar and more complex than my idea.
My idea is basically to create a new keyword syntax as a shortcut for an executed arrow function. It behaves same as arrow function.
Examples:
Transpilation:
We can also use alternative names or keywords for this new feature.
Examples:
Or
We might call
=>
syntax a Immediately Executed Arrow FunctionWe can even pass parameters as an object:
Match Example:
Pipe and Chaining Example
Consecutive chains inherit the single parameter of single field object of parent chain, each assigning return value to that single field object property and passing that as parameters to next chain. We can enforce rule for my proposal to only have one object with one field as the parameter, that field can be be assigned as any object of course.
Alternative Syntax:
We can use for chaining ==> syntax to avoid specifying the parameter with the method:
{value} ==> Filter ==> Map
={value} => Filter(value) => Map(value)
We can of course discuss the syntax, my proposal has 3 suggestions: =>, ->, do. The reason I prefer => is because my method is actually based on anonymous method, just immediately executed, and allowing flexibility.
Thank you,