←back to thread

Go is still not good

(blog.habets.se)
644 points ustad | 1 comments | | HN request time: 0s | source
Show context
torginus ◴[] No.44983258[source]
I still don't understand why defer works on function scope, and not lexical scope, and nobody has been able to explain to me the reason for it.

In fact this was so surprising to me is that I only found out about it when I wrote code that processed files in a loop, and it started crashing once the list of files got too big, because defer didnt close the handles until the function returned.

When I asked some other Go programmers, they told me to wrap the loop body in an anonymus func and invoke that.

Other than that (and some other niggles), I find Go a pleasant, compact language, with an efficient syntax, that kind of doesn't really encourage people trying to be cute. I started my Go journey rewriting a fairly substantial C# project, and was surprised to learn that despite it having like 10% of the features of C#, the code ended up being smaller. It also encourages performant defaults, like not forcing GC allocation at every turn, very good and built-in support for codegen for stuff like serialization, and no insistence to 'eat the world' like C# does with stuff like ORMs that showcase you can write C# instead of SQL for RDBMS and doing GRPC by annotating C# objects. In Go, you do SQL by writing SQL, and you od GRPC by writing protobuf specs.

replies(7): >>44983266 #>>44983314 #>>44983343 #>>44983484 #>>44984652 #>>44985794 #>>44992509 #
gwd ◴[] No.44983343[source]
So sometimes you want it lexical scope, and sometimes function scope; For example, maybe you open a bunch of files in a loop and need them all open for the rest of the function.

Right now it's function scope; if you need it lexical scope, you can wrap it in a function.

Suppose it were lexical scope and you needed it function scope. Then what do you do?

replies(5): >>44983468 #>>44983547 #>>44983606 #>>44983706 #>>44985635 #
gf000 ◴[] No.44983468[source]
Making it lexical scope would make both of these solvable, and would be clear for anyone reading it.

You can just introduce a new scope wherever you want with {} in sane languages, to control the required behavior as you wish.

replies(2): >>44983785 #>>44983852 #
tgv ◴[] No.44983852[source]
Currently, you can write

    if (some condition) { defer x() }
When it's lexically scoped, you'd need to add some variable. Not that that happens a lot, but a lexically scoped defer isnt needed often either.
replies(3): >>44986044 #>>44989906 #>>44994436 #
iainmerrick ◴[] No.44986044{4}[source]
What's an example of where you'd need to do that?

I can't recall ever needing that (but that might just be because I'm used to lexical scoping for defer-type constructs / RAII).

replies(1): >>44993763 #
1. tgv ◴[] No.44993763{5}[source]
Someone already replied, but in general when you conditionally acquire a resource, but continue on failing. E.g., if you manage to acquire it, defer the Close() call, otherwise try to get another resource.

Another example I found in my code is a conditional lock. The code runs through a list of objects it might have to update (note: it is only called in one thread). As an optimization, it doesn't acquire a lock on the list until it finds an object that has to be changed. That allows other threads to use/lock that list in the meantime instead of waiting until the list scan has finished.

I now realize I could have used an RWLock...