Hacker News new | ask | show | jobs
by harikb 1942 days ago
What I meant was if I am Go developer and I write

    for /* whatever */ { 
       fp = os.open(x) // imagine file open
       defer fp.close()
       fp.read()
    } 

    This is wrong. Go linter might tell you it is wrong, but

      a) the defers are pilling up and you might run into too-many-files open
      b) I can never remember if `fp` is saved in defer closure by reference or value. That is, at the end, even if inefficient, are all pending defers closing the same pointer?
Now in a language where "it ends in scope", the scope hasn't ended until the loop exists. Now in the RAII world, the `fp` being overwritten would have saved the day by automatically closing it, but we are not talking about RAII world.

With finally, things are clear, I think.

1 comments

Now in a language where "it ends in scope", the scope hasn't ended until the loop exists. (I assume you mean exits there?)

No, I don’t think that’s correct, in any mainstream language. Each iteration of the loop body is a separate scope. If you declare a new variable inside the loop body, it lives until the end of that iteration then falls out of scope. Next time around the loop, you declare a new, separate variable.

There is a slight grey area around the loop header -- exactly when does the scope start and end? Older C compilers used to disagree about this, but the rules were firmed up in C++ (and I assume in recent versions of C too) and now loop headers use the tightest scope they can.

So I would expect “defer” to run at the end of each iteration, exactly the same as the C++-style RAII case, and that is in fact how it works in every modern language except Go.

Another way to think about it that might be helpful: most languages try to implement defer in a completely static way, where just looking at the syntax, you can figure out exactly where and when defer handlers are going to run. You can allocate all the storage you need at the start of the function, and nothing tricky is required at runtime. If defer handlers are queued up and run as a batch later on, that’s dynamic behavior that needs some extra runtime support, and that’s why most languages don’t do it.

> Each iteration of the loop body is a separate scope.

Thanks for the correction. You are right. I wasn’t thinking straight.