> That aspect of this idea seems similar to the try proposal (
https://go.dev/issue/32437).

Yes, I read over that proposal and the comments; it seemed like the biggest
objections were:
1. handle() is very similar to defer/recover but not quite the same, which
could be confusing (e.g. that a defer() inside a block is just a normal
defer, while a handle() inside a block does not apply outside of that block)
2. It's confusing to take the previous if err != nil {} blocks that were
obviously in response to the preceding line and have the actual handling
code be earlier and far away, and
3. It would encourage people to just pass errors up without modification,
because it's easier to just add a bunch of try's to your code and use the
default handler.

My proposal doesn't have these issues - the handler goes with the try block
so there's no separate function being deferred and no ambiguity about what
code a given handler applies to, the handle block always comes right after
the block being try'd, and there is no "default handler" - you can't use
check to avoid having any error handling, only to consolidate several error
handlers that would be identical.

> In that issue there was considerable resistance to having flow of control
change as part of an expression. No other part of Go works that way: flow
of control change is always a keyword, or a call to panic which can only
occur in statement context.

This is not true - testing.TB.Fatal, log.Fatal, etc. affect control flow,
as do numerous expressions like nil dereferences or zero divisions, and of
course any function call that triggers any of those (and in extreme cases
like running out of memory practically ANY expression could trigger a
control flow change).

The link I provided earlier to the Ondatra package demonstrates that
real-world Go programmers already ARE using expressions for control flow,
by (in this example) calling functions that take a testing.TB and call
t.Fatal() if anything goes wrong; the authors clearly decided that this was
more readable than using idiomatic error handling.

I see panic/TB.Fatal as being somewhat analogous to Java's unchecked
exceptions: they change control flow without warning and you can't be sure
what functions trigger them. Errors-as-return-values is analogous to
checked exceptions: you explicitly mark things you know could go wrong and
the compiler will yell at you if you don't address those possibilities.
Java's single biggest mistake (IMO) was making unchecked exceptions easier
to use than checked exceptions - as a result many developers just didn't do
any error handling at all. Go has mostly avoided this because checking
errors is *usually *easier to write and read than using any of
the aforementioned unchecked methods, but the t.Fatal examples make it
clear that there still are cases where unchecked errors make code easier to
read and write. I'm proposing to fix that, not by making unchecked errors
harder to use or by turning checked errors into unchecked ones, but rather
by streamlining the worst cases in proper error checking, primarily the
all-too-common case where "if ComputeSomething(t, FetchThingOne(t),
FetchThingTwo(t)) > 1" is so, so much easier to read and write than the
equivalent properly checked version (which requires many more lines and
several extra variables).

Dan

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAAViQtjfE2FdauJ888bu1HC%2BZPPCiff5Bz5_N%3DeM2%3DVtx2fFsg%40mail.gmail.com.

Reply via email to