[feature request] self return for chaining (fat arrow variant)
kbtz opened this issue ยท 8 comments
Is there a better solution to implementing chainable "methods" other than adding @
as the last statement? Adding a variant to the fat arrow would be a useful syntax sugar for those writing libraries like Rx.
It would also facilitate custom operators since they usually return the left-hand side:
<unm>: =>
@value = false
@
-- becomes
<unm>: ==> @value = false
btw, thanks for moving moonscript forward..
Not really get the usefulness of this new syntax. It is not saving much typing to offer a coding practice to me. And this will cause conflict with current syntax.
f ==> print 1 -- is currently a function declaration
With your proposal this will be a function call with param of an anonymous function f(==>)
.
It is just my personal opinion. More discussion is welcomed.
Well I think the main point of adopting more flexible languages is to have better expressiveness/readability, not saving keystrokes. The pain point I'm trying to address is for chainable functions to become first-class citizens, that is, having dedicated syntax to avoid repeated code/boilerplate. Useful if one codebase decides to use that style.
I've tried macros but it didn't improve the situation. While I agree that a new operator could be overkill due to low demand, I think that if it were available more people could benefit from multiline chaining which is already implemented.
This NFR is specific to chaining code style but a more useful, general solution would more powerful macros or other meta-programming features. Since I'm not familiar with the parser/compiler internals I might be dreaming here, but how difficult would it be to have a feature that allow code transformes?
Something like: I register the pattern ==>
to be treated as =>
along with a hook that receives the current code context (a function declaration in this case) and use the hook's return value as a replacement if any. It would be nice to have the context received tokenized but a simple string slice would be already powerful engough to solve use cases like mine.
Just some ideas. For now I will try resolve my situation by injecting function wrappers to tables with chainablle methods as I keep forgetting to add that last @
and get nil returns in very odd places ๐
Understood your use cases. Currently we can use macro for a syntax simulation.
macro c = (fun)->
"#{fun}
@"
tb = <unm>: $c =>
@value = false
tb =
new: $c (x, y, z) =>
print x, y, z
chain: $c =>
print "OK"
tb
\new(1,2,3)
\chain!
compiles to:
local tb = setmetatable({ }, { -- 5
__unm = function(self) -- 5
self.value = false -- 5
return self -- 5
end -- 5
}) -- 5
tb = { -- 9
new = function(self, x, y, z) -- 9
print(x, y, z) -- 9
return self -- 9
end, -- 9
chain = function(self) -- 11
print("OK") -- 11
return self -- 11
end -- 11
} -- 8
return tb:new(1, 2, 3):chain() -- 16
And to add it for a new syntax, maybe we can choose other symbols for it to prevent syntax conflict.
I didn't realized we could capture whole blocks as a macro argument, cool! From the docs I had the impression that I would need to use multiline strings for that.
Tried this macro pattern for operators but there still some situations where it is not clear why it breaks:
macro op = (name, fn) ->
"<#{name}>: (value) =>
#{fn\sub 3}
@"
-- this indentation works
t1 = $op add, ->
if something
@value += value
-- even this one
t2 =
a:
b: $op unm, ->
if something
@value = false
-- but this does not
t3 =
$op add, ->
if something
@value += value
$op unm, ->
if something
@value = false
And to add it for a new syntax, maybe we can choose other symbols for it to prevent syntax conflict.
I think =>>
doesn't conflict with valid code (plus its font ligature looks even better ๐).
On the error above, adding bracers to t3 = { ... }
compiles, which is odd because writting the macro output manually doesn't trigger the error:
t4 =
<add>: (value) =>
if something
@value += value
@
<unm>: (value) =>
if something
@value = false
@
Maybe some identation issue on the macro result? Is there a way to have more verbose diagnostics for macros when using the lua module?
t3 = $op add, -> if something @value += value $op unm, -> if something @value = false
The $op add, ->
is seen as a complete expression instead of key value pair for a table to the compiler. So this code is the same as:
t3 =
($op add, ->
if something
@value += value)
($op unm, ->
if something
@value = false)
and this won't compile. Macro in Yuescript currently can only be an expression or a code block. You can't replace other AST such as key value pair with it.
Just implement a new feature for adding default return expression for a function. And the chaining function you mentioned could be written as:
tb = <unm>: =>
@value = false
@
-- becomes
tb = <unm>: (): @ =>
@value = false
And this syntax prevent the implicit return behavior for a function.
tb = <unm>: (): @ =>
@value = false
if @value
-- no longer returning the last line to prevent unintended behavior.
doSomethingWith @
When you have too many nested levels of indents in a function body, you can make use of the syntax to append a default return at the end.
f = (): result ->
result = false
if checkOne!
if checkTwo!
result = true
compiles to:
local f
f = function()
local result = false
if checkOne() then
if checkTwo() then
result = true
end
end
return result
end
Just played with it on the website and I see it will make my functions more readable to me. Thank you!
When you have too many nested levels of indents in a function body, you can make use of the syntax to append a default return at the end.
This will be very useful too.