News for hackers. Stuff that matters.
Re:Looking into Zig by Groxx on Friday August 06, 2021 @11:42PM (#28095488)
Purely on the topic of `errdefer`, I believe the equivalent in Go would be:

    // must use named returns so you can observe the returned error
    func yourfunc() (result thingtype, err error) {
      thing := constructIt()

      defer func(){
        if err != nil {
          thing.Close()
        }
      }()

      // use thing to do a few things that could error
      err = thing.setup()
      if err != nil {
        return nil, err
      }
      other, err := thing.other()
      if err != nil {
        return // naked returns are fine too
      }
      // etc
    
      return
    }
Which is...... technically possible, and not even all that bad (as much as I strongly dislike named returns, since I find them very error-prone), but the fact that I have not ever seen this done does sorta reveal how much friction there is. Instead, I usually see manual additions of err-cleanup to relevant branches, and I've seen that pattern fail repeatedly as well (especially when the code is modified much later by some other person).

The Zig equivalent seems like it would be roughly (I don't know Zig)

    func yourfunc() thingtype {
      thing := constructIt()
      errdefer thing.Close()

      // use thing to do a few things that could error
      try thing.setup()
      other = try thing.other()
    
      return thing
    }
which is quite a bit more palatable and future-mistake-resistant. A sizable chunk of that is due to `try` of course, but still.
Re:Looking into Zig by slimsag on Saturday August 07, 2021 @03:11AM (#28096467)
Actually, not only are you right about your errdefer Go implementation - but that's actually fairly common in Go code.

Especially for tracing/logging of errors returned from functions; or for e.g. rolling back DB transactions in the event of an error.

Here's some ~100 examples from my work's (Sourcegraph's) codebase[0]

[0] https://sourcegraph.com/search?q=context:global+repo:%5Egith...

Re:Looking into Zig by ziml77 on Saturday August 07, 2021 @10:50AM (#28098985)
I'd be interested to see if someone who works regularly with Go can show a cleaner way to do this. Because what I'm seeing here is just reinforcing my biases against Go. I've tried Go a couple times before but only ever read about Zig and yet I still find the Zig far easier to follow. It's much less verbose without being less explicit.

(Also I'm not sure if the compiler would catch this, but there seems to be a bug in that Go code that's hard to see at a glance. You're never assigning a value to result)

Re:Looking into Zig by Groxx on Sunday August 08, 2021 @09:29PM (#28111831)
I work regularly in Go - for an isolated example, that's about as clean as it gets. If you want to make it a little more middleware-y you could do this:

    func iferr(err *error, f func()) {
      if err != nil { f() }
    }
    
    // use
    func whatever(...) (err error) {
      thing := ...
      defer iferr(&err, thing.Method)
    }
But that only works with an exact match, so that example can't match e.g. `Close() error`, so you still have to either make a ton of near-clones for different signatures, or use a ton of trivial closures (like with the manual version), to make the type system happy.

Which can be worth it in a large enough project - `func()` and `func() error` will take care of like 90% of the signatures you'd defer anyway. I'd probably do that personally, unless I only needed it once or twice.

There has been a somewhat similar check/handle proposal (close to "try"), but it has consistently fallen into "they're great for trivial cases, but they make it harder to have good error messages / wrap errors with additional context", which is absolutely necessary in Go since errors are so loosely typed and contain only explicitly-added information (no stacks by default, for example). So I'm glad they haven't happened yet.

Re:Looking into Zig by Groxx on Monday August 09, 2021 @05:02PM (#28122300)
Ah, and: yes! You're right, it does fail to return any `result`. That was unintended, and as-written it won't complain, since `thing` is "used" (methods are called on it) and `result` does not need to be used: https://play.golang.org/p/iSU5YWyxODC
Re:Looking into Zig by mjbrusso on Saturday August 07, 2021 @07:22AM (#28097702)
The equivalent in Visul Basic would be:

On Error Goto line

Re:Looking into Zig by benibela on Saturday August 07, 2021 @03:37PM (#28101223)
Or in Pascal

   try
     ...
   except
   end
wrapped around the error/exception generating code
Re:Looking into Zig by tored on Saturday August 07, 2021 @08:26AM (#28098087)
Deserves an upvote. Not everyday you see praise about Visual Basic.

Looked this up and line can also be a label. Great.