However, by having them be function scoped, this isn't so anymore; e.g, a defer occurring in an if() statement needs to happen at the end of the function, but only if the if occurs. If you loop over a defer, we need to accumulate those. (And the golang tour even explicitly calls the behavior out.[1]) So, instead of just running the defer at the end of the if / inside the if statically, we need to push the defer onto a runtime stack of yet-to-be-run defers that we'll evaluate at the end of the function. This now has to happen at runtime, not compile time, and makes the function compilation more complex, and requires a stack somewhere to push this stuff onto.
From a compiler writer's perspective, I would agree w/ the parent: this seems much more complex, and runs counter to golang's otherwise simple design philosophy.
†Though the linked list that the compiler has to generate could hit malloc, which costs more than a few nanoseconds.
EDIT: I just re-did the relevant tests on Go 1.11.5. It's significantly better than in 2014 but it still costs between ~20us and ~50us ("only" 4 orders of magnitude more than "a few ns").
goos: linux
goarch: amd64
BenchmarkPut-8 50000 27502 ns/op
BenchmarkPutDefer-8 30000 46774 ns/op
BenchmarkGet-8 50000 29812 ns/op
BenchmarkGetDefer-8 20000 89701 ns/op
PASS
[1]: https://lk4d4.darth.io/posts/defer/However, I think this change was mostly just an optimization for common cases with few arguments or no closures (e.g. "defer f.Close()").
Putting the defers on the stack is also part of how the runtime unwinds the stack during a panic.
All exception ABIs on all major platforms can do this without any overhead in the no-exception case. The compiler embeds static metadata (in a subset of DWARF, on Linux) alongside the function, and the unwinder parses that metadata in order to determine which destructors to invoke.
If you're using recover, it's probably time to rewrite the func.
I say this because Go forces you (minus just ignoring with _) to error check; so panic's shouldn't happen to start with.
Errors are for when the input (specifically the I/O) is wrong, a precondition isn't met, or some other error that doesn't mean there is something fundamentally wrong with your code.
If to make the problem go away you need to fix the code, panic is OK.
fmt.Println("foo")
Where did golang force you to error check?How about (taken from here: (https://www.reddit.com/r/programming/comments/ak305l/goodbye...):
r1, err := fn1()
r2, err = fn2()
if err != nil {
return err
}