3 ms·
This is not about (runtime) performance. Like the the article mentions, the block-end version lets you implement everything without dynamic allocations and (I g
by unscaled 6y ago
This is not about (runtime) performance. Like the the article mentions, the block-end version lets you implement everything without dynamic allocations and (I guess) pointer de-reference. The C3 implementation of block-end defer described in the article is zero-cost, as far as I can see.
I suspect the real reason is the driving force behind a great deal of the early Go 1.x design choices: making the compiler simpler. Or, if you wish: _compiler_ performance.
Go 2.x is shaping up to be a different beast, but Go 1.x had an extremely strong design philosophy favoring compiler simplicity (which often equates to compilation speed) over nearly every other concern, including runtime performance. That's exactly one of the main argument that was used against having generics: (non-erased) generics significantly improve performance, but slow down the compiler.
I'm personally very much in disagreement with this philosophy, but I don't think all these design choices are baffling or even misguided - they clearly achieve what they were set to do.
- sltkr 6y agoI think the reason is much simpler: block-scoped defer isn't useful if you statements appear in a nested construct. Example: fd := OpenSocket(...); if fd != 0 { defer CloseSocket(fd); } // do stuff For the same reason, Go's defer cannot be implemented without dynamic allocations. For example, how would you implement: func foo(int n) void { for i := 0; i < n; i++ { var res = bar(n); defer fmt.Println(res); } } This calls bar(0), bar(1), etc. then prints the results of bar(n - 1), bar(n - 2), etc. There is no way to implement this without some way to store the intermediate values.
- ttt0 6y agoCompiler should be able to figure out at compile time whether the dynamic allocation is needed. But maybe the Go compiler already does this, I don't know.
- sltkr 6y agoTrue, I was talking about the general case. This is a bit similar to local variables: they have to be allocated on the heap in the general case, but Go uses escape analysis to determine which local variables can safely be allocated on the stack instead, which is much cheaper.