Add `defer` keyword
applejag opened this issue · 0 comments
Another parity keyword added from Go.
I suggest the exactly same semantics, meaning:
- Must followed by a function call
- The function and arguments are captured at the point of the
defer
statement - The deferred function is called at the end of the function (and not at the end of the block)
Edge cases
Outside any function
When called in the main file outside any function, the deferred call should be executed at the end of the entire program.
// example-1.risor
defer print("world")
print("Hello")
$ risor example-1.risor
Hello
world
Use in REPL
When used in the Risor REPL, it should be called when exiting. If it isn't already, the REPL needs to start listening for Ctrl+C and react to it, instead of just exiting.
$ risor
Risor
>>> defer print("hello world")
>>> ^C
hello world
Inside imports
To reduce hidden behavior, when called outside any function inside an imported file, it should be called at the end of import.
// otherfile.risor
defer print("deferred print inside otherfile.risor")
print("print inside otherfile.risor")
// example-2.risor
import otherfile
print("print inside example-2.risor")
$ risor example-2.risor
print inside otherfile.risor
deferred print inside otherfile.risor
print inside example-2.risor
Motivation
Useful when working with io.Closer
types, such as os.create()
:
f := os.create("foo.txt")
defer f.close()
f.write("hello world")
Alternatives
Just to get some perspective. I'm personally in favor with the proposal I made above.
Python with
statement
Python's with
statement is quite enticing, but I've a personal reluctant feeling for it just because of the extra code block, and the fact that the variable name is at the end.
On the other hand, a benefit is that you get full control over when the scope ends.
with open("foo.txt", "w") as f:
f.write("hello world")
With Risor, it would probably look something like this:
with f := os.create("foo") {
f.write("hello world")
}
Downside is that you can then only use this on io.Closer
types.
C# using
statement
C# has a using var ...
declaration that is a simplified using () { }
statement. It calls Dispose()
on the object at the end of the block.
The nice thing about this shorter version is that it doesn't add extra indentation, similar to Go's defer
keyword.
void Foo() {
using var file = File.Create("foo.txt");
var text = new UTF8Encoding(true).GetBytes("hello world");
file.Write(text, 0, text.Length);
}
In Risor, it could look something like this:
using f := os.create("foo.txt")
f.write("hello world")