3 ms·
I don't like the possibility of nested handle() blocks. This could make grasping the control flow in a function very cumbersome. Everything else looks like a
by the_duke 8y ago
I don't like the possibility of nested handle() blocks.
This could make grasping the control flow in a function very cumbersome.
Everything else looks like a very good change to me and would draw me back in to Go.
- pcwalton 8y agoYeah, the control flow of "handle" is the most questionable thing, from my standpoint. (Incidentally, I find the function-scoped nature of "defer" unfortunate too.)
- kenhwang 8y agohandle/check looks like try/catch in reverse order with check/try limited to statements instead of code blocks. Not sure if that's an improvement or just different for the sake of being Go.
- timClicks 8y agoI have noticed that my Python code increasingly works like this via the optional else clause in its try/except mechanism.
- jerf 8y agoI've thought about that before, as I participated in one of the bugs where we chewed on these various matters, and I came around to the conclusion that in general, understanding what is in your current scope is just the cost of doing business. Being scope-based is the minimal cognitive load you can hope for. I also strongly suspect that in the general case, you're not going to see more than one handler at the top of the function. It will be a rare function that has a dozen of them in there, and either A: it needs to be refactored, and while I'm sorta sympathetic to the idea that we shouldn't hand programmers too much rope to hang themselves with, that argument has the problem that you end up removing pretty much everything from the language or B: it's the core inner complicated loop of a program and it just needs that much complexity, which still doesn't mean it's going to show up in every function. It's not that dissimilar from one function getting nested four layers deep in try/catch statements; yes, it would be a bit confusing to disentangle what that would actually do (moreso, since the catch statements are conditional but the handlers are not), but the answer is simply not to do that unless you really need to, and thwack any coworker that tries it on the wrist during code review. It is impossible to make a Turing-complete language in which I can't express something incomprehensible in.
- the_duke 8y agoI actually like the explicit error handling idiom a lot. (especially in Rust now that is has been made convenient with the ? operator and the failure crate which provides backtraces and wrapping). I would prefer an extension of the `check` syntax instead of the standalone handle blocks. For example: check someFn() |> if err : = someFn(); err != nil { return err; } check someFn() handle { panic(err) } |> if err := someFn(); err != nil { panic(err) } So handle blocks are only for an individual expression. This way the control flow is still linear and explicit (ignoring defer...) but the syntax is much more convenient.
- pcwalton 8y agoYeah, this is the obvious approach. Just make "check EXPR handle BLOCK" syntactic sugar for the "if err != nil" idiom. It's totally clear to the reader what's going on.
- deleted 8y ago[deleted]
- kjeetgill 8y agoIt's obvious because it's essentially just try/catch (as I'm sure you know) but misses the whole point of why they propose anything different. The point of 'handle' is that it applies to ALL FUTURE calls to check in the function body. If we're going to consider alternatives we need to at least address the authors perspective (even if just to deny it). I guess the proposal's central idea is that once you see an error, error handling is going to be focused on rolling back various stages of partial progress. It's the complement to how 'defer' incrementally accumulates guaranteed execution in the face of either a return or unwind. That said, how common this issues is and if it's worth optimizing for is more up to debate. It would be nice to see a lexicon of well handled errors; for 90% most of what I do log and unwind is sufficient. What do I know -- I actually like Java style checked/unchecked exceptions and think they'd work well for Go as the parent said. For what I'm up to it's often sufficient to just not leak partial progress via side effects. All the partial progress just evaporates into the GC. 'finally' or 'defer' takes care of most of the .close() or .unlock() calls. The change I'd make to Java-style exceptions if I had a time machine is to make all exceptions types unchecked. Instead of looking at exception's types at all, enforce checks only if a function has 'throws' declared. Calls to 'void close() throws IOException' would still need to be checked but a function containing 'throws new IOException()' isn't forced to declare throws or catch it. This lets API's be explicit and force due diligence but lets user code intelligently allow unwinding until it's caught at the appropriate level. Some sugar for code to acknowledge the checked error and unwind could be nice I suppose. I think fattening out Go's err's to full exceptions with stacktraces is more pressing personally.