8 ms·
More Gotchas of Defer in Go, Part II
- brabel 9y agoEvery point mentioned was not a gotcha to anyone who read the official introductory tour of the language. The behaviour may be unexpected to newbies, but if you spent an hour or so learning the language, you shouldn't be falling for these.
- inancgumus 9y agoCheck out the first part too: https://blog.learngoprogramming.com/gotchas-of-defer-in-go-1-8d070894cb01 https://blog.learngoprogramming.com/gotchas-of-defer-in-go-1... I fell to these when I was learning Go for the first time and then I've seen many people also did so. There is no rule like these are gotchas for everyone.
- bsaul 9y agoCompletely agree. This is probably the most comprehensible list of programming language « gotchas » i’ve ever read. It feels really a confirmation that the language authors have succeeded in their goal for simplicity.
- jitl 9y agoAlso read the official blog post on defer: https://blog.golang.org/defer-panic-and-recover https://blog.golang.org/defer-panic-and-recover It covers about half of these gotchas by laying out how the defer statement works in plain English. The other half (like how closures work inside loops in Go) are covered elsewhere in the language tour. I do really like the visualizations! Makes it very clear how these mechanics work.
- jerf 9y agoThe content is good, and it is accurate, but even though defer can be a bit tricky this blog post series seems to literally be describing the entire semantics of "defer" as "gotchas". It's not that tricky!
- inancgumus 9y agoWell, it depends. Upgoing posts will go deeper on defer.
- inancgumus 9y agoThanks! That post definitely a must read. Btw, the first part was more advanced (but again for beginners and intermediate gophers) -> https://blog.learngoprogramming.com/gotchas-of-defer-in-go-1-8d070894cb01 https://blog.learngoprogramming.com/gotchas-of-defer-in-go-1...
- barell 9y agoI think most of the people who understand the basic principles of how computers (and many languages) work wouldn’t be surprised by any of the „gotcha” described in this article. It seems to be written for people who just started working with golang without any or little knowledge about information technology.
- pcwalton 9y agoThe semantics of many languages' for loops are explicitly designed to avoid this problem: for example, for-of in ES6. Generally, modern language design considers the interaction between loop iteration variables and closure captures. It's reasonable to criticize Go as a language for not addressing this problem rather than users.
- readittwice 9y agoI am not sure about this. Swift for example also has `defer` statements but its behavior differs from Go's. Swift executes defer statements at the end of the block, not the end of the function. And AFAICR Swift doesn't evaluate the parameters right away like Go does. If you have already read how defer works in detail in Go, you probably already know this. Devs new to the language or those that haven't used defer in those cases might still be surprised when this shows up.
- deleted 9y ago[deleted]
- KirinDave 9y agoIn only surprised because so many of them are such well-known things to avoid when designing a language and runtime.
- knorker 9y ago#4 can also be fixed with: for i := 0; i < 10; i++ { i := i // Creates a *new* `i` defer func() { … something with i … } go func() { … something with i … } }
- poorform 9y agoThis is too sneaky and seems like poor form. I'm curious what good use-case there is for this, that the language bothered to support and allow this to even compile. Duplicate variable name declaration + referencing in the same scope is unintuitive at best, and just seems wrong.
- pcwalton 9y agoShadowing can be useful if you want to make sure the "old" variable is never referenced again in the same scope. The reason why this idiom feels "weird" is that the loop construct of the language really ought to automatically make a fresh instance of the loop counter for each trip through the loop.
- knorker 9y agoI don't feel that it's in more poor form than the solution suggested in the article: for i := 0; i < 3; i++ { defer func(i int) { fmt.Println(i) }(i) } This shadows `i` pretty much the same amount as what I wrote. If `i` gets a different name inside the lambda, then it'd also be worse because then you could accidentally use `i` still.
- tylersmith 9y agoI personally prefer the version presented in the article, but your version has at least one nice feature in that you can cleanly specify at the top of the loop body which variables are being shadowed.
- arundelo 9y agoIt would be nice if Go made a new i for each iteration of the loop. Lua 5.0 made just one loop variable per loop, like Go apparently does. When I first ran into this behavior, I thought that, although it wasn't what I expected, it made at least as much sense as what I was expecting. Since then, every single time I've been in a situation where the two ways of doing it gave different results, I've wanted the "separate variable for each iteration" behavior, so I was glad when Lua's creators changed loop variables to work like this in Lua 5.1. (Before this change I would just do the Lua equivalent of your "Creates a new `i`" line.)
- br1 9y agoIt's indefensible that defer works on the function and not on the scope.
- willvarfar 9y agoWell I think the function scope the most useful, but wish there was block scope available too. So what I really wish was that languages used dot notation to go up scope eg ..name is that name two blocks out. This was one of the good parts of VB syntax which I miss in other languages. Think how much nicer it is than python's nonlocal and global, for example!
- br1 9y agoIt's true that defer is more powerful at function scope. You can always recover block scope with an unnamed func. But it doesn't fit with normal lexically scoped constructs. You get gotchas. I would love to be able to explicitly affect other scopes as you mention, for example to define two classes at the same time.
- pcwalton 9y agoWhat's the use case for function scoped defer? I have never once needed function scoped RAII in C++ or any other language.
- br1 9y agoCollecting tasks from all iterations to await before returning.
- pcwalton 9y agoFair enough. But it's something like 5 lines of code to write that manually, and writing it explicitly is clearer. With implicit function-scoped defer, someone might refactor the code to inline the body of the function into its caller and break it.
- 9y ago
- brian-armstrong 9y agoDefers just feel like a watered down version of what you get with good scoping and RAII. They're a half measure for something programming languages solved decades ago.
- mratzloff 9y agoGo has a garbage collector. RAII is only viable in languages where destruction is predictable, like C++ or PHP.
- int_19h 9y ago"defer" is effectively used for predictable destruction in Go, and a more automated RAII scheme could be used in its place. C++/CLI is a language that targets a garbage-collected runtime, yet has full-fledged RAII semantics (they're mapped to CLR Dispose pattern).
- mratzloff 9y agoOh, I totally forgot about C++/CLI! You're absolutely right; that's my mistake. I do agree that RAII is preferable.
- pcwalton 9y agoThe tracing GC certainly complicates things, but you can make it work with a "scope" keyword like in D.
- pjmlp 9y agoPHP also has a garbage collector. Swift and D also have garbage collectors and support RAII. And since I already see it coming, reference counting is a garbage collection implementation algorithm in computer science literature.
- mratzloff 9y agoYep, and I even referred to reference counting earlier in the week as garbage collection, so I'm going to assume I was having memory corruption with my answer. :-)
- ramenmeal 9y agoI code in go every day professionally. These are not gotchas, they are well defined behaviors.
- inancgumus 9y agoCheck out the first part too. Btw, gotcha means what you say: "a gotcha ... works as documented but is counter-intuitive and almost invites mistakes ..." https://en.wikipedia.org/wiki/Gotcha_(programming) https://en.wikipedia.org/wiki/Gotcha_(programming)