In defense of blocks for local scopes
gist.github.com
gist.github.com
I also use this in Lua. The benefit there---once the scope is over, the variables declared in the scope become available for garbage collection. In a small function, this isn't that much of a win, but for the top level scope, it probably is. You can see an example of this in my gopher server [1]. Don't let the formatting confuse you, this:
local CONF = {} do
local conf,err = loadfile(arg[1],"t",CONF)
if not conf then
io.stderr:write(string.format("%s: %s\n",arg[1],err))
os.exit(exit.CONFIG,true)
end
-- rest of code
end
is the same as local CONF = {}
do
local conf,err = loadfile(arg[1],"t",CONF)
if not conf then
io.stderr:write(string.format("%s: %s\n",arg[1],err))
os.exit(exit.CONFIG,true)
end
-- rest of code
end
The 'do' keyword introduces a new scope (and can be used anywhere to do so). I format it as the former to be more explicit about the CONF variable being defined by the following code block.[1] https://github.com/spc476/port70/blob/master/port70.lua#L41
Yes, to me it does. I love when variables have really tight scopes so I don't need to worry about if/how they are used throughout the rest of the program. Locality should be the default, not something that needs to be justified.
Creating a function is just unnecessary boilerplate if the code is not going to be reused. Functions are just named blocks with arguments. But if you don't need to name the block and don't need to reuse it with varying arguments, creating a function is just unnecessary.
Functional programmers are familiar with a concept called "let", which essentially gives you a way to introduce a variable and introduce a new scope just for that variable. This article is essentially just showing how to do that in JavaScript.
[1] honestly, not so little
I admit to using block scopes in rust a fair bit
with open("foo") as f:
s = f.read()
print(f) # closed file object still exists
A macro that looks like a context manager would work but beware the edge cases.It could take zero arguments if you just want to temporarily extend the current scope with a few more variable-binding statements. Or, it could also have arguments if you want to do a "let" like construct to rename some expression results in the outer (calling) scope during the invocation.
# ... outer scope
x = expr1
y = expr2
r1 = None
r2 = None
def block1():
nonlocal r1
z = expr3
r1 = expr4
block1()
def block2(x, y):
nonlocal r2
z = expr5
r2 = expr6
block2(expr7, expr8)
Edited for typos, code formatting, and bugs ;-). /* do */ {
const foo = “bar”
do_the_stuff(foo)
} /* while(JS_sux) */
Typing code on a phone is hard…There's also a GCC extension for this! https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
I'm using this for something a bit like Rust's unwrap (but uglier):
#define UNWRAP(expr) \
{{ \
auto result_ = (expr); \
if (!result_.present()) panic(); \
result_.disown(); \
}}
optional<int> foo();
void bar() {
int val = UNWRAP(foo);
}Fun read.