`on err` alternative to `try()` has traction...?

394 views
Skip to first unread message

Liam

unread,
Jul 2, 2019, 7:57:24 PM7/2/19
to golang-nuts
This proposal has attracted modest attention from the Go team...

It suggests:

err := f()
on err, <single_statement>

on err, return err // any type can be tested for non-zero on err, return fmt.Errorf(...) on err, fmt.Println(err) // doesn't stop the function on err, continue // retry in a loop on err, goto label // labeled handler invocation on err, hname // named handler invocation


And offers these possible extensions:

on err, os.IsNotExist(err):  <stmt>
on err, err == io.EOF:       <stmt>
on err, err.(*os.PathError): <stmt>    // doesn't panic if not a match

on err, <condition>: <stmt>
on err: <stmt>              // this pair provides if/else in 2 lines

on err := f(), <stmt> // for assignment with single lvalue


Other punctuation is possible, e.g. on (err) <stmt>

Now if we could just convince the Go gods to prototype this along with try() in 1.14 :-)

Michael Ellis

unread,
Jul 3, 2019, 1:26:32 PM7/3/19
to golang-nuts
I like this. A lot.

It's clean and explicit.  The reader only needs to understand that 'on' is a test for a nil value (vs 'if' which tests for boolean true).

Aston Motes

unread,
Jul 3, 2019, 6:36:08 PM7/3/19
to Michael Ellis, golang-nuts
This proposal is not very much different from a one-liner

if err != nil { <single_statement> }

It's just 10 more characters. Granted, gofmt won't leave the one-liner formatted that way, but it's not much more typing and comes with the benefit of not needing a new keyword.

One variation on this proposal that is a little weird is that if could in the case of checking for an error omit the requirement that its argument be a boolean, giving

if err { <single_statement> }

Which is only 3 characters longer than on and again avoids a new keyword. I believe changing the behavior of if this way should be backwards compatible.

--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/decc63a5-9e65-4e96-929f-76d44cf19e14%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Michael Jones

unread,
Jul 3, 2019, 10:26:28 PM7/3/19
to Aston Motes, Michael Ellis, golang-nuts
Any form of restraining gofmt has my vote. One that I despise is ruining:

switch v {
case ‘a’: doA = true
case ‘b’: doB = true
:
case ‘z’: doZ = true 
}

Just had this two days ago. So sad to see it balloon up


For more options, visit https://groups.google.com/d/optout.
--
Michael T. Jones
michae...@gmail.com

Bakul Shah

unread,
Jul 3, 2019, 11:24:07 PM7/3/19
to Michael Jones, Aston Motes, Michael Ellis, golang-nuts
May be indent(1) can be taught about Go syntax rules so that it can "pretty-print" ala Lisp?
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CALoEmQy5E5%2BK%2BKAcCvVZFJDWptNdfkAz1NrSUVa4oM%3DuQxTgOQ%40mail.gmail.com.

Slawomir Pryczek

unread,
Jul 4, 2019, 8:55:50 AM7/4/19
to golang-nuts
On one side, it's 1000x better than the other error handling specs, at least it isn't going to turn code into unreadable, fragmented mess. On the other, Aston seems to have a point, it's just replacing one-liner... and it's not that great at all because with "if" you know what it's doing without reading the spec.

My point is it doesn't fix anything, it doesn't provide any clear benefit... it's an attempt to fix something which works great and is clearly not broken. So why complicate the language with a new keyword which has really no purpose. Maybe adding a warning about unhandled errors to VET would be better idea (which would probably be complicated to do properly, but at least it'll have some real, positive effect on code quality).

Michael Ellis

unread,
Jul 4, 2019, 3:14:40 PM7/4/19
to golang-nuts
As noted by Aston, Jones, et al, the proposal is combining two ideas that are separable:

  1. Allowing one-liners. I like the idea of leaving that to gofmt. I'd be ok with requiring braces and allowing gofmt to make the decision to format in one line or three using some reasonable criterion.
  2. A test for not nil.  In my view, saving a few keystrokes is not the reason to support such a test. I've already got an editor snippet that generates a default "if err != nil ... " clause.  It just seems to me that "on err { doSomething }" is worth allocating a keyword for the (admittedly minor) gain in readability.  Note: The actual proposal is more general than that. It defines 'on' as a test against the zero-value for the variable's type. I'm not sure that's a good idea. Seems messy if it were allowed to struct types.

mh cbon

unread,
Jul 4, 2019, 8:45:40 PM7/4/19
to golang-nuts
yes the zero value test seems akward from here also.

It appears to me the proposal is sub optimal because,
to put it clear, the operator is dumb.
Its a disguised if with a one lin block statement.

I believe it would gain a ton more usability by being smarter to allow for more useful predefined/expected
behavior.

this statements really looks like misformed

on err, os.IsNotExist(err):  <stmt>
on err, err == io.EOF:       <stmt>
on err, err.(*os.PathError): <stmt>

less stupid the oprator could infer various things based on static rules,
very much like value/ptr initialization implies a few static rules.

on os.IsNotExist(err):  <stmt>
on err == io.EOF:       <stmt>
on err.(*os.PathError): <stmt>

robert engels

unread,
Jul 4, 2019, 8:56:07 PM7/4/19
to mh cbon, golang-nuts
--
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...@googlegroups.com.

Liam Breck

unread,
Jul 6, 2019, 6:09:21 AM7/6/19
to golang-nuts
I've expanded the proposal to address feedback from the Go team. It now offers a more special purpose construct than the generic if-variant 'on'.

See the Critiques section in


--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/4Djft8snCjM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/1b7ab9bd-0c1b-4658-8ee2-a36544b58f20%40googlegroups.com.

Lucio

unread,
Jul 7, 2019, 9:42:45 AM7/7/19
to golang-nuts


On Thursday, 4 July 2019 22:45:40 UTC+2, mh cbon wrote:

less stupid the oprator could infer various things based on static rules,
very much like value/ptr initialization implies a few static rules.

on os.IsNotExist(err):  <stmt>
on err == io.EOF:       <stmt>
on err.(*os.PathError): <stmt>
 
That starts to look like a switch statement, which is not a bad thing, in its own right. Maybe not what OP or follow-ups intended.

Lucio. 

Nicolas Grilly

unread,
Jul 9, 2019, 10:42:33 AM7/9/19
to golang-nuts
On Thursday, July 4, 2019 at 10:55:50 AM UTC+2, Slawomir Pryczek wrote:
going to turn code into unreadable, fragmented mess

Do you really think that replacing:

f, err := os.Open("file.txt")
if err != nil { 
  return err
}

By:

f := try(os.Open("file.txt"))

Will "turn code into unreadable, fragmented mess"? Isn't it a bit of an overstatement?
 
My point is it doesn't fix anything, it doesn't provide any clear benefit... it's an attempt to fix something which works great and is clearly not broken.

try fixes error handling verbosity, while keeping the language grammar and semantics unchanged. I respect that error handling verbosity is not an issue for you, but when you wrote that it is "clearly not broken" you're denying it can be an issue for other Go developers.
 
So why complicate the language with a new keyword which has really no purpose.

As mentioned in the proposal, try is not a new keyword, it's just a new built-in function.

Maybe adding a warning about unhandled errors to VET would be better idea (which would probably be complicated to do properly, but at least it'll have some real, positive effect on code quality).

The compiler and vet already report unhandled errors. 

Nicolas Grilly

unread,
Jul 9, 2019, 11:48:21 AM7/9/19
to golang-nuts
On Thursday, July 4, 2019 at 5:14:40 PM UTC+2, Michael Ellis wrote:
In my view, saving a few keystrokes is not the reason to support such a test. I've already got an editor snippet that generates a default "if err != nil ... " clause.

The goal of the try proposal is not to "save a few keystrokes".  The goal is to reduce error handling verbosity when reading code.

Jan Mercl

unread,
Jul 9, 2019, 11:57:44 AM7/9/19
to Nicolas Grilly, golang-nuts
On Tue, Jul 9, 2019 at 1:48 PM Nicolas Grilly <nic...@vocationcity.com> wrote:

> The goal of the try proposal is not to "save a few keystrokes". The goal is to reduce error handling verbosity when reading code.

It's not verbosity. It's error handling. And because error handling is
usually not the happy path, it's good when it stands out clearly. That
improves readability as the important part catches attention easier.

Hiding important code in one line instead, or with even using nested
try constructs, makes the important path easier to overlook or to not
be aware of it at all. For me personally, try buys zero advantages at
the cost of several disadvantages.

PS: Maybe we all somehow confuse readability with comprehensibility.

Ian Davis

unread,
Jul 9, 2019, 12:00:57 PM7/9/19
to golan...@googlegroups.com
On Tue, 9 Jul 2019, at 11:43 AM, Nicolas Grilly wrote:
 
So why complicate the language with a new keyword which has really no purpose.

As mentioned in the proposal, try is not a new keyword, it's just a new built-in function.

It's quite a bit more than a just new function since it brings some new behaviours that we don't have for functions in Go at the moment:

1. like panic it interrupts its caller's control flow

2. It may only be used within functions/methods that have a particular signature. Presumably it's a compile error to attempt to use it elsewhere.

3. It accepts any number of mixed type arguments without boxing into an interface{}

Ian



Henrik Johansson

unread,
Jul 9, 2019, 12:03:32 PM7/9/19
to Jan Mercl, Nicolas Grilly, golang-nuts
Not sure if anyone has already mentioned the possibility that "try" could actually improve error handling
by simply removing much of the tediousness. Both reading and writing all the error checks becomes a
nail in my eyes even if realize that it is very important. What if "try" could take some of that annoyance
away and simply make me focus on handling the errors where appropriate and pass on where convenient?

--
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...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAA40n-W50W92FEKhf4tbSR%3D6wFr3Cc5u1QVWu%2BXnwQWpUCaMQw%40mail.gmail.com.

Jan Mercl

unread,
Jul 9, 2019, 12:27:21 PM7/9/19
to Henrik Johansson, Nicolas Grilly, golang-nuts
On Tue, Jul 9, 2019 at 2:03 PM Henrik Johansson <dahan...@gmail.com> wrote:
>
> Not sure if anyone has already mentioned the possibility that "try" could actually improve error handling
> by simply removing much of the tediousness. Both reading and writing all the error checks becomes a
> nail in my eyes even if realize that it is very important. What if "try" could take some of that annoyance
> away and simply make me focus on handling the errors where appropriate and pass on where convenient?

Consider a factorial function:

func factorial(n int) int {
if n < 2 {
return 1
}

return n*factorial(n-1)
}

In the above function the check for n less than 2 is conceptually the
same as checking for an error/exceptional condition/value.

Seems that no one argues that the if statement in this function is
"verbose", "disrupting" or whatever.

I, for one, consider the if statement, regardless of it checking for
number or error value, always equally important. Trying to hide it
makes no sense to me.

But maybe the community really prefers the C version:

int factorial(int n) { return n < 2 ? 1 : n * factorial(n-1) }

Me not.

Liam Breck

unread,
Jul 9, 2019, 1:03:28 PM7/9/19
to golang-nuts
The controversy between try and explicit error checking is why I wrote this proposal, to provide a compromise that's both explicit and terse.

Nicolas Grilly

unread,
Jul 9, 2019, 1:20:07 PM7/9/19
to Jan Mercl, golang-nuts
On Tue, Jul 9, 2019 at 1:57 PM Jan Mercl <0xj...@gmail.com> wrote:
It's not verbosity. It's error handling. And because error handling is
usually not the happy path, it's good when it stands out clearly. That
improves readability as the important part catches attention easier.

I agree that the "sad" path is as important as the "happy" path, but I wouldn't say it's more important to the point of dominating the number of lines in a function. In some functions, 2/3 or 3/4 of the lines are dedicated to error handling. 
 
Hiding important code in one line instead, or with even using nested
try constructs, makes the important path easier to overlook or to not
be aware of it at all. 

try "hides" nothing. try is only useful for returning the error. If there is some important error handling code in the if statement block, then try cannot be used and the code stays the same.

Don't you think we could get used to try after using it a bit? This is what happens to Steve Klabnik when the ? operator was added to Rust. He was against it, and changed his mind after writing code using it.

Nicolas Grilly

unread,
Jul 9, 2019, 1:31:38 PM7/9/19
to Ian Davis, golang-nuts
On Tue, Jul 9, 2019 at 2:00 PM Ian Davis <m...@iandavis.com> wrote:
It's quite a bit more than a just new function since it brings some new behaviours that we don't have for functions in Go at the moment:

1. like panic it interrupts its caller's control flow

2. It may only be used within functions/methods that have a particular signature. Presumably it's a compile error to attempt to use it elsewhere.

3. It accepts any number of mixed type arguments without boxing into an interface{}

try is not a new function, it's a new built-in function. The behaviours you are mentioning are normal for a built-in function. Robert Griesemer has already commented about this several times in the issue tracker, for example here: https://github.com/golang/go/issues/32437#issuecomment-509337453

Wojciech S. Czarnecki

unread,
Jul 9, 2019, 1:36:48 PM7/9/19
to golan...@googlegroups.com
On Tue, 9 Jul 2019 15:19:22 +0200
Nicolas Grilly <nic...@vocationcity.com> wrote:

> I agree that the "sad" path is as important as the "happy" path, but I
> wouldn't say it's more important to the point of dominating the number of
> lines in a function. In some functions, 2/3 or 3/4 of the lines are
> dedicated to error handling.

Because given piece of contemporary production code may succeed in
only ONE way, but it may FAIL in many ways.

--
Wojciech S. Czarnecki
<< ^oo^ >> OHIR-RIPE

Nicolas Grilly

unread,
Jul 9, 2019, 1:49:48 PM7/9/19
to Wojciech S. Czarnecki, golang-nuts
On Tue, Jul 9, 2019 at 3:36 PM Wojciech S. Czarnecki <oh...@fairbe.org> wrote:
Because given piece of contemporary production code may succeed in
only ONE way, but it may FAIL in many ways.

If a piece of code may fail in many ways, then it will probably have several if blocks, and try will not be used. I don't see how this is an argument against try… 

Dan Kortschak

unread,
Jul 9, 2019, 10:14:02 PM7/9/19
to Nicolas Grilly, Wojciech S. Czarnecki, golang-nuts
This is not necessarily true. A single call may return a variety of
errors. Otherwise a simple (ok bool) would be enough.
Reply all
Reply to author
Forward
0 new messages