Repository navigation
Description
I am planning on introducing a new expression which is basically just a statement list. You can think of it like
local foo = (function()
print("hello world!")
return 1
end)()
print(foo)except that the syntax would be
local foo = do
print("hello world!")
return 1
end
print(foo)Except that the return in this case returns from the entire function, not from the blockexpr.
(Refer to this issue for discussion about which keyword to use)
Honestly the fact that this needs a new keyword is a gigantic downside, but if we can find a decent keyword for it I consider it worth it.
Since we are also still within the same function that the expression is in, keywords like break and goto can actually link to loops and labels outside of the expression. I thought about it and I don't see any issues with this.
The inspiration for this expression is that it is just a simpler form for the imo disgusting syntax for immediately invoked function expressions which is (function() return expr end)()... or worse (() => expr)().
We already use the former, with lambda expressions we will do the latter, and ultimately I believe it is worth improving this syntax.
Additionally, lambda expressions can be simplified thanks to this blockexpr by simply always expecting an expression. In fact, lambda expressions would just end up being syntatic sugar for function() return <expr> end. Think about lamba expressions like
(foo) => print(foo)() => do print("hi") return 1 end
It just works.
Lastly note that this will always - somehow - be an opt in language feature due to the introduction of a new keyword which can potentially break Lua code.
That all said, I'm asking for feedback on this, if it is feature creep or not.
Activity
mspielberg commentedon Nov 24, 2021
I would greatly prefer if it were just a block that ends in an expression without a keyword:
Then a lambda is
local oneAdder = (x) => do x + 1 end.JanSharp commentedon Nov 24, 2021
Hm. Having heard and learned about expression languages recently I can understand where you're comming from. I even thought about the
blockexprjust being a block of many expressions where the last expression ends up being the result, which to my knowledge is an expression language thing, but decided against it because it's a completely new concept that Lua isn't made for. (you couldn't use any statements in there at that point).Now a statlist followed by an expression is interesting... However I believe it suffers from the same issue that it's a completely new concept in Lua. Compare
with
Not only is it a new and very different concept, but it also looks just as different.
Because of that I'm leaning towards a no. Not because I think expression languages are bad, but because Lua (and with it Phobos) is not made for it
mspielberg commentedon Nov 24, 2021
As mentioned on Discord, with expression-if it gets better:
In an expression language, a list of expressions just has the resulting value of the last expression in the list. So:
Then do-end would be less special, and just the same as the immediately-invoked-function version.
JanSharp commentedon Nov 24, 2021
Yea that's true, and I understand that and I agree. But I feel like it would only make sense if it really was a block of just expressions where the last one then gets returned.
Which would then need an expression form for all statements (fun fact: there are actually more statements than expressions), at which point you'd be writing completely different kind of code in this context. It might look similar, but you have to think about it differently - and that specifically is what I consider to be problematic. The coexistence of both systems in such close proximity (an expression language inside a statement+expression language (whatever that's called)).
The "statlist followed by just one expression" approach would be less work, but suffer from the same issue as described above, plus that people who know expression languages might end up reading the entire block as expressions, which is them comming to the wrong conclusion which then leads to confusion.
Lastly, hardly anybody who knows Lua would expect that kind of behavior when reading Lua-like code. I care about readability and with it maintainability a lot.
I would say an expression-language mode for Phobos would be possible... and while it would definitely be possible, chances of me implementing it are incredibly low, because of reasons such as feature creep and a significant increase in complexity.
So yea, once again I can see where you're comming from, but the more I think about it the less I see it in Phobos. Sorry :/ .
curiosity-a commentedon Nov 24, 2021
There is something important to consider: do you want
doto become an expression statement, like the function call?If yes, what sense does the return from blockexpr make in the statement form, especially when you can do the same with
goto? Does it even fit Lua, considering that is one of your criteria?If no, what keyword do you want to start it with,
blockexprbeing the obvious choice?In any case, do you allow the classical "omit the brackets" call syntax when the blockexpr is the only argument? And there is, of course, goto, which shouldn't be able to jump out of the blockexpr and into the scope of the variable that said blockexpr was supposed to initialize.
JanSharp commentedon Nov 24, 2021
Yes to some degree, see next paragraph.
A "blockexpr" in the statement form isn't a
blockexpr, but adostat. while they would both be using the same keywordsdo end, they would still be separate and theblockexprretstatwould not have any meaning in adostatmaking this a non-issue.As said above, it would also use
do end. Technically it could use a differnet open_token, but I have thought it through and could not think of any possible currently valid Lua code that would break withdo endsuddenly being a valid expression. And in terms of terminology I don't see any issue withlocal foo = do print("hi") <ret> 100 end=> "do this work, which means printing 'hi', then return/evaluate to 100 which ends the work, then assign the result to the new localfoo".Nope. The fact that you can omit parenthesis for function calls is good for table constructors, but a curse for literal strings. Extending that to the
blockexprwould just be spreading the curse.gotojumping intoblockexpris most likely going to be forbidden, yes, because chances are high it would be a jump into unassigned tempraries. Jumping out ofblockexprs however is perfectly valid, as long as you do not jump into the scope of an unassigned variable (or to the end of a block, just before new vars go out of scope). This matches howgotoworks in general.curiosity-a commentedon Nov 24, 2021
This also makes the syntax inconsistent, the
doand return from blockexpr keywords - context-dependent.Just drawing attention to the fact that the variable being declared is unassigned until and unless said declaration statement is completely executed (as opposed to being interrupted by
goto).