I second that, I actually don't understand why do people believe every pair of curly braces has to be its own separate scope. An explicit construct for scoping would have been so much clearer to me.
> I actually don't understand why do people believe every pair of curly braces has to be its own separate scope.
It’s much easier to reason about when your variables aren’t going to escape past the end of the block.
In non-GC languages going out of scope can also be a trigger to free the contents of the variable. This is useful for situations like locking where you can put the minimal span of code that requires the lock into a scope and take a lock which automatically unlocks at the end of the scope, for example.
JavaScript’s hoisting and scoping feel natural to people who started in JS, but most people who came from other languages find it surprising.
GCed languages often also have a mechanism for running code on scope exit. For example Lua's <close> attribute, which runs a metamethod when it goes out of scope rather than having to wait for GC:
function readfile(name)
local f <close> = assert(io.open(name))
return assert(f:read"a")
end
In most languages, each block indeed is a separate scope. And it avoids foot guns about accidentally using variables that already serve another purpose. I guess it's one of the things that are typical for dynamic languages.