5 ms·
A somewhat related technique which I often find useful is something that’s known as “immediately invoked function expressions” (IIFE) in JavaScript. That also c
by jotaen 4y ago
A somewhat related technique which I often find useful is something that’s known as “immediately invoked function expressions” (IIFE) in JavaScript. That also creates a sub-scope in place, but it let’s you return values to the enclosing scope. E.g.:
result := func() string {
helperVar1 := //...
helperVar2 := //...
return helperVar1 + helperVar2
}()
So it’s basically an anonymous function that is invoked right away. You could achieve the same scope separation by pulling it out as named function, but sometimes I like it better to keep things closer together.
- throwaway894345 4y agoThis is really helpful in Go for `defer`. For example, if I'm manipulating files in a loop, I don't want to do: for _, fileName := range fileNames { f, err := os.Open(fileName) if err != nil { return err } defer f.Close() doSomething(f) } ... because I might run out of quota for open file handles. I want the defer to trigger at the end of the loop rather than at the end of the function, so I'll often put a closure in the loop body: for _, fileName := range fileNames { if err := func() error { f, err := os.Open(fileName) if err != nil { return err } defer f.Close() doSomething() return nil }(); err != nil { return err } } That said, I don't like the ergonomics and if I'm doing a lot of file things, I'll write a `func withFile(fileName string, callback func(*os.File) error) error` function which often composes more nicely.
- arp242 4y agoI use this for package globals especially: var pkgGlobal = func() string { ... }() Much better than: var pkgGlobal string func init() { pkgGlobal = ... }
- shadowgovt 4y agoConceptually yes, but IIUC there should be worlds of difference at the compilation output level (i.e. unlike calling a function, the compiler's not obligated to set up or tear down a context every time it enters or exits a block; it can just treat the static scope semantics without having any impact on the runtime semantics). ETA: except for go's `defer`, and off the top of my head I don't actually know if Go is obliged to run the defer immediately upon exiting the block or can choose to run it at some other point in the function.
- Jtsummers 4y agoIn Go, `defer` runs at the end of the enclosing function, not the enclosing block.
- vlovich123 4y agoThat shouldn’t be the case for c++ and Rust lambdas that are immediately invoked. The compiler should see through it.
- slaymaker1907 4y agoNot necessarily for C++. At least for msbuild, you can use `__declspec(noinline)` on a lambda. This can be handy for complex macros that would otherwise allocate a bunch of memory.
- ollien 4y ago> unlike calling a function, the compiler's not obligated to set up or tear down a context I guess it depends on what you mean by "context" but the spec is very clear that a block creates scope, and the end removes scope. https://go.dev/ref/spec#Declarations_and_scope https://go.dev/ref/spec#Declarations_and_scope > The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block.
- avgcorrection 4y agoYet again the heavy initialism that looks like it came right out of a C++ standards document is just a long name for a simple thing.