proposal: Go 2: on err or catch statement for error handling

The try() proposal #32437 has met with significant complaint, especially about
a) lack of support for decorating/wrapping returned errors
b) lack of support for widespread alternatives to returning error, e.g. log.Fatal(), retry, etc.
c) obscured function exit
d) difficulty of inserting debugging logic
If a separate line is usually required for decoration/wrap, let's just "allocate" that line.
f, err := os.Open(path)  // normal Go \o/
on err, return fmt.Errorf("Cannot open %s, due to %v", path, err)

(This may overlap too much with if ... { <stmt> }. An error-specific variant is given in Critiques no. 1.)
This plugs easily into existing code, as it leaves the err variable intact for any subsequent use.
This supports any single-statement action, and can be extended with named handlers:
err := f() // followed by one of

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
on err, ignore                // logs error if handle ignore() defined

handle hname(clr caller) {    // type caller has results of runtime.Caller()
   if err == io.Bad { return err } // non-local return
   fmt.Println(clr, err)
}

Keyword on borrows from Javascript. It's preferrable not to overload if.
A comma isn't essential, but semicolon doesn't seem right. Maybe colon?
Go 1 boilerplate is 20 characters on 3 lines: if err != nil {\n\t\n}\n
This boilerplate is 9 characters on 1 line: on err, \n
Specifics
// Proposed
on expression, statement

// Equivalent Go
var zero_value T // global, not on stack
if expression != zero_value {
   statement
}

// Disallowed; these require a named handler or function call
on expression, if/for/switch/func { ... }
on expression, { statement; statement }

The expression is constrained to ensure that its use (if any) within the statement is correct. For example, expression cannot be a function call or channel receive. It could be limited to an lvalue, literal, or constant,
Possible Extensions
For an assignment or short declaration with a single lvalue, on could test that value. (Note, I don't recommend this; better to have on err consistently on its own line.)
on err := f(), <stmt>

An error inspection feature would be helpful...
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

A condition list suggests parentheses:
on (err) <stmt>
on (err, <condtion>) <stmt>

Critiques

The above may be too general-purpose. A post-assignment alternative is:
err := f()
catch <stmt>                  // test last var in preceding assignment for non-zero
catch (err == io.EOF) <stmt>  // test last var and boolean condition
catch (ep, ok := err.(*os.PathError); ok) <stmt>  // assignment preceding condition

This doesn't accommodate narrowly scoped error variables if err := f(); err != nil { ... }. A way to scope the variable to the stmt is:
_ = f()
catch err, <stmt>
catch err, (err != io.EOF) <stmt>

go fmt could just allow single-line if statements:
Would it also allow single-line case, for, else, var () ? I'd like them all, please ;-)
The Go team has turned aside many requests for single-line error checks.

It's as repetitive as the current idiom:
on err, return err statements may be repetitive, but they're explicit, terse, and clear.

@gopherbot add Go2, LanguageChange

I was just thinking how inlining a handler would look like.
on err, {
  do()
  things()
  return err
}

The comma doesn't feel right in that case.
This makes me think if using curly brackets instead of the comma is an option. However, the code then becomes more like the boilerplate that we have already with if.

I would opt for a =: reverse nil operator that does the same but keeps the clean line of side
err := f() // followed by one of
err =: return err            // any type can be tested for non-zero
err =: return fmt.Errorf(...)
err =: fmt.Println(err)      // doesn't stop the function
err =: continue              // retry in a loop
err =: hname err             // named handler invocation without parens
err =: ignore err            // logs error if handle ignore() defined

handle hname(err error, clr caller) { // type caller has results of runtime.Caller()
   if err == io.Bad { return err } // non-local return
   fmt.Println(clr, err)
}

/cc @daved @brynbellomy @guybrand

@networkimprov

on err, return err            // any type can be tested for non-zero

The comma between "on err, return" bugs me, as comma is most commonly used between two variables.
it doesnt look much like go syntax

Quoting @griesemer from https://github.com/golang/go/issues/32437#issuecomment-501878888
(And was also the approach on the try() proposal itself) :
"minimal idea which addresses one part of error handling well"

I think the above proposal offers a wide variety of solutions as you stated:

The try() proposal #32437 has met with significant complaint, especially about
a) decorating/wrapping returned errors, and
b) lack of support for widespread alternatives to returning error, e.g. log.Fatal(), retry, etc.
And even some more, but I'm not sure there's a bandwidth to address it, I tried to advocate a rating mechanism for try() or any other proposal (BTW, can be a good concept not only for the Go 2 error handling improvements but a general cost-effective per major development effort criteria), but I dont see the concept is well understood, If there's no bandwidth the options are:
a. Narrow down the proposal to be "affordable" - and try to compromise as little as possible.
b. Perfect it as much as possible, so perhaps one day when it will be affordable it would be a lead option
c. break it down to sub requests so perhaps it can be implemented in steps.

@networkimprov I agree a conditional return without assignment (ie, not try) on it's own line make a lot of sense, and seems to strike a good balance between being clear, and convenient.
, bugs me as well, and is a new meaning fro the seperator.
on <x> ==  if <x> != nil does not seem like the best meaning for the word "on"
What if it was just 1 line if statements with semicolon as the seperator? (not sure how this jives with the lexer)
if err != nil; return err
if err != nil; return fmt.Errorf(...)

There is already a history of using ; in a similar way
if thing, err := doThing(); err != nil {
...
}

This proposal is missing the "precise statement of the proposed change" part.
It is difficult to infer that precise statement from examples.
As best I can tell, the proposal is to add
on X, Y

where X must have type error, and which expands to
if X != nil { Y }

Is that a correct and complete statement of what you are proposing?

@rsc, thanks for pointing that out. I've added a Specifics section, which says
// Proposed
on expression, statement

// Equivalent Go
var zero_value T
if expression != zero_value {
   statement
}

The expression is constrained to ensure that its use (if any) within the statement is correct. For example, expression cannot be a function call or channel receive. It could be limited to an lvalue, literal, or constant,

As you hinted at yourself, the proposed syntax doesn't gain much over just putting the equivalent if statement in one line:
if err != nil { return err }
on err, return err

I don't think it's worth making a breaking change to the language for something you can almost get with a gofmt tweak.

I don't get the point of "but if we have on line if-statements". We do now have them, and AFAIK the go team doesn't want them. We don't have them for a reason. If we add them that would pretty much nullify this proposal, but that doesn't mean that this proposal is any worse because of it.
this has a clear advantage over on-line if-statements, it is very clear what is going to happen, and is less general then an if-statement. You cant just use this wherever.

I support this proposal.
It is important that any change to error handling allows each error in a function to be annotated explicitly and independently from other errors. Returning the naked error, or using the same annotation for every error return in a function, may be useful in some exceptional circumstances, but are not good general practices.
I also support using a keyword instead of a builtin. If we add a new way to exit a function, it is important that it isn't nestable within other expressions. If we have to wait until further improvements to the language allow this to be accomplished without breaking the Go 1 compatibility promise, then we should do that, rather than make the change now.

@peterbourgon Can you explain why you think on err is so much better than if err != nil that we need new syntax?
Also, there is a mantra that every error needs to be decorated somehow. I agree that this is important at the library boundary level. But there are plenty of package interior functions where decorating an error is not needed; in fact it only leads to over-decorated errors. Can you expand on the statement of bad practice that you are referring to?

@griesemer

Can you explain why you think on err is so much better than if err != nil that we need new syntax?

To be clear, I'm in the "leave if err != nil alone" camp, like many other veterans of the language. But it seems like the core team has decided this is a "problem" that's worth solving, and I have sympathy for the perspective that it might encourage more not-yet-Gophers to become Gophers, so I'm speaking from that assumption.

Also, there is a mantra that every error needs to be decorated somehow. I agree that this is important at the library boundary level. But there are plenty of package interior functions where decorating an error is not needed; in fact it only leads to over-decorated errors. Can you expand on the statement of bad practice that you are referring to?

I think this is one of many points that demonstrate a disconnect between the core Go team and Go as it is used in practice.  They are almost exclusively private, and their developers infrequently respond to surveys. As I see it, this is the primary market for Go the language.
In these contexts there are almost no packages which are imported by more than one binary. In fact I'd estimate that ~50% of Go code I've seen has just been in package main. What's more, these developers rarely have enough time or experience to properly structure the main business logic of their programs, much less think deeply about the structure or cleanliness of their errors. Many, many people have the instinct to write functions like this, and use them everywhere:
func checkErr(err error) {
    if err != nil {
        panic(err)
    }
}

So, given that, and given that package boundaries are rarely well-defined, the risk is not over-decoration. Many of these developers have to be convinced to even return errors in the first place, rather than just calling os.Exit or log.Fatal. If new syntax allows developers to essentially search-and-replace their home-made checkErr functions with the apparent blessing of the language developers, well, I fear we've just moved the resiliency and coherence of most Go codebases backwards, not forwards.

Thanks, @peterbourgon for your detailed comment. We've picked up error checking because the community has repeatedly and strongly complained about the verbosity of error handling. And yes, we also think that it might be nice if there were a less verbose approach where possible. So we're trying to move this forward if we can.
From what you're saying, try would already be a big step up from checkErr - for one it takes care of dealing with an error in the first place, and it also promotes at least an error return rather than just a panic. Because it removes the need for a checkErr function and extra call on a separate line, I'd expect those checkErr programmers to flock to try.
I see your point that on err might be easier to change into proper error handling (i.e., decoration), but again, judging from the reality you are describing it seems that checkErr would still be the much easier way out. If these programmers have rarely enough time or experience to do error handling "properly", why not provide a tool that gives them a strong incentive to check and forward errors? And rather than insist on decorating each error separately, use a deferred error handler (which can be one line)? This seems like a much easier sell than having them replace checkErr with an on err statement.
(As an aside, I've written plenty of little tools that just panic when I don't care about the error - not great, but good enough when time is of the essence. try would make my life much easier and allow me to do something better than panic.)

@peterbourgon @griesemer, the last few comments haven't considered that on err provides handling of recoverable errors; not just ones that return. These are very common, and try is no help to them.

I've added error inspection to the Possible Extensions section:
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

Does this proposal reinvent C semantics for if and calls it on?  The statement is executed if the expression is non-zero. The two differences are that C allows compound statements (aka blocks) and supports additionally an else branch.

If we're at a new keyword, why not generalize it as an "alias" to the
if var != zero_value { block }. Current whines about 'verbosity of error handling' IMO stem mostly not from the language spec per se but from the parser shortcut then gofmt rules that make simple if three lines high (whats not that bad as the stuttering != nil ;).

"on" statements specify the conditional execution of a single branch according to the immediate result of a boolean expression, or a boolean result of an implicit comparison of the non-boolean value of an expression with the zero value of its type. If the result of either is true, the "on" branch is executed, otherwise it is not executed.

OnStmt = "on" [ SimpleStmt ";" ] Expression Block.
on err {
    return err
}
on !err {"\n"}
on ok := call(); ok {"\n"}
on call(); !ok {"\n"}
on !(x%d) {"\n"}
on a - b {"\n"}

Then after a slight reduction, we may just add this pinch of implicit nonmagic
to the "if" itself: "if the Expression value is not of boolean type...".
Magic semicolon rules, with the closing parenthesis relaxing rule are more magic than that.
if err {
    return err
}
if !err {"\n"}
if ok := call(); ok {"\n"}
if call(); !ok {"\n"}
if !(x%d) {"\n"}
if a - b {"\n"}

The real change would be to allow single statement blocks to occupy a line. But in fact I now value that space hinting at the possible change of the control flow.
@ulikunitz Yes, indeed :)

I think the boilerplate that counts is what people see.
This reduces three lines to one line.
It reduces if err != nil {} to on err,, which by my count is reducing 12 characters to 6.
This adds a new kind of constrained expression which does not exist elsewhere in the language.  The suggested extensions seem to mostly try to unconstrain the expression a bit by writing || as ,.
To me personally I don't think the savings are enough to justify the language change.

@ianlancetaylor

the savings are enough to justify the language change.

For me personally with try there are none savings only more mud. I am voting for the status quo, but if we're thinking changes lets think about what possible outcome of stepping back to C if expression semantics. Being implicit it might even tackle at immortal if interface == nil gotcha.

@ianlancetaylor there's nothing like try() (either its arguments or effects) in the language now either, so apparently it's ok to devise novel schemes to reduce error handling boilerplate :-)
The feature on err offers which try() lacks is application to virtually all errors, including recoverable ones.
Sure, the concept needs work to support a variety of use cases in a way that blends with the rest of Go.

I did not mean to imply that it was not OK to devise novel schemes.  But any novel scheme is a cost, which must be balanced by some benefit.  I was listing the benefits and costs I see of this scheme.

The bet here is that on err use at almost all call sites that yield an error delivers far greater benefit for essentially the same cost. Actually lower cost, since control-flow cannot become buried, and integration into existing code is trivial.
If data from a revised tryhard bears that out, what argument would remain for try()?

@ianlancetaylor
Regardless of liking (or not) the on err syntax,  whether it needs more/less work and whether "it look like go", I dont think its very comparable to try() as it does not aim "to remove some boilerplate in the error handling", but rather tries to give a complete set of error handling that will remove the boilerplate for readability yet allow most of the functionality (inc. error decoration, flow control etc).
And although there will probably not be two paths for error handling improvement (well - Is/As...), on the one hand, and that on err is suggested as "an alternative", I would suggest to "judge" on err as an independent proposal, and only then compare cost<>effective vs try()

@griesemer
I'm sorry to have overemphasized checkErr, I didn't mean to suggest it was the default case in code that I review, I only wanted to use it as an example of how error handing in "real world" Go is probably a lot less sophisticated than one might think.
I'm pretty sure more explanation from me won't help to sell my case any more at this point, but I do want to respond to one thing:

I see your point that on err might be easier to change into proper error handling (i.e., decoration) but . . . rather than insist on decorating each error separately, use a deferred error handler (which can be one line) . . . seems like a much easier sell . . .

Prior to the check/handle proposal, I had never once considered, or seen in the wild, the general pattern of decorating errors with a deferred function. (The only times I'd ever used a deferred function to interact with errors were in the exceptional cases where that pattern was more convenient for complex resource cleanup.) While I understand your perspective that a one-line deferred error handler may seem like an easier sell—less typing, and less repetition—my experience tells me that I'd have a much harder time selling that sort of "look over here!" indirection as a general solution to novice programmers, versus short, in-situ repetition of on err expressions—of which we already have a reasonably effective (if more verbose) version in if err != nil.
I'd like to make one final and higher-level point. I believe the try proposal significantly under-values the costs of physically separating error handling from the error-generating statements. It seems to me that if you boil Go down to its barest essence, one of the properties that surely must remain is (waving my hands and trying to paraphrase a lot of stuff here) that errors are not exceptional, that the "sad path" of code is at least as important as the "happy path", and that the control flow from error handling should not be treated any differently from the control flow of business logic. It seems pretty clear to me that try subverts this essential property, and that on err does not.

On 7/3/19, Peter Bourgon<EMAIL_ADDRESS>wrote:

[ ... ]
I'd like to make one final and higher-level point. I believe the try
proposal significantly under-values the costs of physically separating error
handling from the error-generating statements. It seems to me that if you
boil Go down to its barest essence, one of the properties that surely must
remain is (waving my hands and trying to paraphrase a lot of stuff here)
that errors are not exceptional, that the "sad path" of code is at least as
important as the "happy path", and that the control flow from error handling
should not be treated any differently from the control flow of business
logic. It seems pretty clear to me that try subverts this essential
property, and that on err does not.

I think you and I see things pretty much the same way, if it makes you
feel any better.
My weak proposal is that we suck into the invoked function the
responsibility to report what you call the need to treat the "sad
path" (one of a number) on exit as if it were as common as the one,
usually) "happy path" and use a different "return" command to do so:
we expect the invoker to respond to the "sad" situation differently
and we use a different reporting method to emphasise the difference.
I was just making a note to myself that the identity of the invoked
(and failing or "unhappy") function should not be part of the
decoration of an error message, because that would be repeated within
the function as many times as there are unhappy exits, whereas the
invoker only needs to add that decoration at the site of invocation.
That in some way connects to the "deferred error handling" presented
as the counter to your proposal. I think the more explicit "on err" or
my own also explicit "fail" are clearer and more flexible.
The reality is that Rob Pike's "errors are values" is too powerful a
meme to be messed with until one realises that the problem that needs
solving is not verbosity, but repetition: it's that  "if err != nil
{", that bugs everyone and an abbreviation that conveys in one word
that the invoker needs to be informed of one additional condition
should probably not be solved by subsuming that condition "in band"
with less optional parameters.
Putting it another way: each "sad" exit from a function is different,
normalising them all into one-size-fits-all has a price and too much
of Go's philosophy depends on accepting (as I do) that the price is
worth paying. If you don't like that price, the answer is not a
"better Go", it is a "different" Go.

@peterbourgon As much as I'd like the try proposal, I have to admit that the "indirection" necessary to decorate the error with a deferred function is convoluted, and could be difficult to teach to novice Go programmers. I hope that another iteration of the proposal will lead to the right solution.

Then let us not change the language.

Then let us improve the try proposal 😉

errors are not exceptional [...] the "sad path" of code is at least as important as the "happy path"

I think we all agree with this. The issue is that each time we query an external system, and this query can fail in multiple ways, we have 1 line to query the system, and 3 lines to check, decorate and return the error. This makes the "sad path" three times more visible, more significant, than the "happy path".
I notice we are not the only ones struggling with this. Rust, Swift and Zig, for example, are looking for the right solution to this issue.

@ngrilly

The issue is that each time we query an external system, and this query can fail in multiple ways, we have 1 line to query the system, and 3 lines to check, decorate and return the error.

This on err proposal reduces it to one, which I think is the Pareto optimal number of lines, for the reasons I've discussed. Can not on err be the improved try?

@peterbourgon Thanks for your response.
It has become clear from much of this discussion that many are disappointed that try doesn't do more for error handling. Maybe it's not emphasized enough, but the proposal is clear that if decorating/handling an error at the point of the error check is desired, the existing if err != nil pattern is the recommended approach. We are at this point not convinced that there is anything else to do in that case (but see below).
But there is the legitimate use case where errors are simply returned. And there is the legitimate use case where all errors returned from an API entry point are decorated uniformly (the same way) - which is where the deferred handler is suggested (which is independent and orthogonal to try). We hear that these cases may not be the majority of cases, but they are not negligible, and they are the cases where the boilerplate becomes egregious because it adds only clutter. In those cases I would want to factor out that code, like one would with everything else that's repeated and the same, but because we can't do this in Go (and won't be able to do this in any foreseeable future version of Go), the helper function try seems like a good compromise. It's truly a minor addition to the language. If it doesn't fit a specific program design, don't use it.
I think there's a fundamental misunderstanding in this general discussion (not between you and I), a fear that try is the "must-use" mechanism for error handling, or perhaps more accurately, that try might become the "must-use" mechanism. That is not our intention, nor does the proposal say as much.
Regarding the need for a more comprehensive error handling construct: philosophically, Go has never been in the business of promoting a specific programming paradigm (notwithstanding the fact that it is an imperative, statically typed, type-safe language). For instance, Go supports OO programming but doesn't mandate it. Instead it provides all the building blocks (methods, interfaces, embedding) to achieve that. Go supports exception handling but doesn't encourage programming with exceptions via a try-catch construct. Instead it provides the building blocks (panic, defer, etc.) to do so if desired. That is not to say that Go is not opinionated - of course it is. But that opinion is not enforced so much by the language but by convention and by tools (go fmt, go vet, go lint, etc.).
Whether the language or the tools enforce a paradigm doesn't make much of a difference for a specific piece of software at a given time, the outcome is the same: a certain style is encouraged or enforced. But it matters in the long run: conventions can evolve as we learn more, and tools can change and adapt. Existing programs will continue to run. On the other hand, if we enshrine paradigms into the language it will become much harder or impossible to change them because it might invalidate a lot of existing code.
For that reason I am much more reluctant to make more significant language changes such as adding "on err" or the like. try is simply factoring code. "on err" is adding a new paradigm.
At this point, I think the question we need to answer is this: Is it reasonable to add a minor built-in to the language that facilitates error checking for a significant number of cases (but not most), and which can be safely ignored if one desires to do so, or is even that not justified and we should leave the language alone.
Thanks.
(*) Adding the predeclared type error was of course the first (and perhaps the biggest) step in this direction: It enshrined that errors should be of error type. But my making them more abstract (as error is an interface type) it increased interoperability between components while introducing a standard, yet the remain "just values". This was clearly a win-win.

Is it reasonable to add a minor built-in ... or is even that not justified and we should leave the language alone.

You already have a loud & clear answer to that question from the community.
Re "minor" built-in, please consider whether that's a rationalization.

@guybrand I am not comparing on err to try; I am comparing it to if err != nil.

@ianlancetaylor
Your right, I read the correspondence over the mobile, it was actually the response to your comment that compared (and not for the first ... or last in this thread ...)
Sorry, I will correct.

Regarding the line

For that reason I am much more reluctant to make more significant language changes such as adding "on err" or the like (*). try is simply factoring code. on err is adding a new paradigm.

I'm curious about how is try simply factoring code when it's able to make the function return?
Not criticizing, just trying to figure out why try is seen as something "simple", while on err is a new paradigm.

Alright, I hacked tryhard to report the necessary counts (diff here: https://github.com/griesemer/tryhard/compare/master...balasanjay:tryhard-data), and ran it over the Go corpus 0.01 (https://github.com/rsc/corpus).
I believe there's lots of vendoring and such in the corpus, so there is likely to be double-counting. Also, I didn't spend very long on hacking tryhard. Caveats aside, here's the data:
| All code | All code (%) | Non-test code | Non-test code (%) | Test code | Test code (%)
-- | -- | -- | -- | -- | -- | --
COUNT-1-STMT-RETURN | 202932 | 57.22% | 200999 | 70.07% | 1933 | 2.85%
COUNT-1-STMT-OTHER-SINGLE | 114447 | 32.27% | 57966 | 20.21% | 56481 | 83.32%
COUNT-2+-STMTS | 34711 | 9.79% | 25960 | 9.05% | 8751 | 12.91%
COUNT-1-STMT-OTHER-COMPOUND | 2064 | 0.58% | 1902 | 0.66% | 162 | 0.24%
COUNT-0-STMTS | 486 | 0.14% | 26 | 0.01% | 460 | 0.68%
Note: tryhard only operates on functions which return an error as their last response type, I removed this filtering to be fair to this proposal, so not everything on the first row can be handled by try.

@campoy try is just a macro, fashioned into a built-in function. If we could write try in Go, one might write it and use it like any other function we use to factor out shared code (one sort of can, using ugly hacks with panic and defer, for specialized calls, but that's beside the point). try doesn't introduce new syntax or new keywords; and since it lives in the universe scope, it can be shadowed like any other name. As a consequence, it won't affect any existing code.
on err is a new statement and requires a new keyword. It will interfere with any code that uses on as an identifier. It also overlaps directly with the if statement, something we try to avoid for major language constructs. The syntax on err, <statement> is unusual for Go, one would expect on err { ... }. I don't know why there needs to be a comma. Details.
Of course we could say that on err is simply a form of syntactic sugar for a common pattern, very much like try. And that if one could write on err in Go some would (like some would with try).
But there is really a difference between a built-in function and a new statement. Built-ins can easily be ignored (because they don't interfere with existing code). With few exceptions (len, append), they can be skipped when learning the language, and introduced on demand. In the spec they show up at the end. Several built-ins are not strictly "needed" and one could write the same code by hand (append, copy, complex come to mind) - these are here purely for convenience. try falls into this category.
A statement cannot be ignored - it is either used or it must be avoided (in the sense that we cannot have identifiers that collide with keywords of statements).  It must be learned by everybody for that reason. In the spec it shows up prominently.
Generally, a statement in Go doesn't enshrine a single use case: An if statement is simply for conditional branching, a for statement for looping, a switch statement for selecting between many alternatives, and so on. They operate on arbitrary data types and in different kinds of coding styles.
But an on err statement is only for checking and handling errors. There's no other use case. As such it will become the recommended way of checking errors, even though there is absolutely nothing wrong with if err != nil {}. So on err - by sheer existence - promotes a certain coding style, or what I called a paradigm (maybe paradigm is not the best word).
Not only does on err overlap with if, it also does not make code a lot more compact. Code that is now dominated by if err != nil will become dominated with on err - there's not much gained, and a lot lost (introducing a new language statement comes at a big cost).
try also has a very narrow use case. It's only good for one thing: checking an error and return. But it doesn't affect existing code. Because it's much more narrow than on err, the savings are much bigger. It's also more powerful than on err because it can be used in an expression, something we can't do with on err. Yet it comes at much less cost. It doesn't scream "you must use me for error handling" in the language spec. It's just a little built-in for convenience (see above). It terms of complexity of implementation it is trivial compared to say append, copy, etc. It is tremendously helpful in many situations, very much like append is, but it doesn't have to be used.
One more thing, unrelated to your question: We (the Go team) have considered many many alternatives (some of which I mentioned in the design doc). But for minor syntax differences, most alternative proposals brought up in this public discussion we have already considered one way or the other (we have been discussing error handling internally on a regular basis for more than a year). We ended up with try because it seemed to have the least negative impact on existing code and the language, and because it seemed easy to explain and very clear. Where it can be used it has a big impact on the readability of the code (in our minds) because it reduces so much boilerplate. It opens new avenues of use because it can be used in expressions where before we needed separate statements. The same cannot be said for most alternative proposals that have been brought up so far (but the ideas that make error checking invisible and implicit - nonstarters). But it does require getting used to. It's a bit of a shift in thinking about errors. It only solves error checking, not error handling. It takes time. And maybe the time is not now, and maybe try is not it. We don't know without try-ing :-)
Apologies for the lengthy reply (I didn't take enough time to make it shorter). I hope this helps explaining a bit better what I tried to say here.

I think there are two insurmountable issues with try, the function:
the obligation to deal only with functions that have a common, but
very unique and in a sense "weird" signature (the last argument is of
type "error") and the implicit "return".
Each of these flies in the face of the Go philosophy and is an
aesthetic failure. Imagine providing the two "features" as individual
(that is, not necessarily combined) properties of arbitrary, user
defined functions. Extending the compiler in that direction without
offering the same ability to the developer is what "smells", I
believe.
Would the designers really like to define and implement such
extensions for arbitrary use? Are they going to make sense in a user
manual? And yet, internally and quite visibly, they will
become"available", but just to this one "macro".
It's too small a target for such a big projectile.
Worse, it may be a great idea if it IS implemented as suggested, but
with a view to EXPERIMENT (is that an option?) and to nurture it until
the seed develops into something that can be offered to Go developers
as a compatible or otherwise way to deal with error conditions.
Rob Pike first identified something that is special to Go - errors are
values. But that made us forget that we like to think of errors as
rare exceptions when in fact they are less "common", but more
"numerous" than normal function terminations. Are the words I picked
sufficiently clear in distinguishing these situations?
Doug Gwyn would suggest not dealing "in-band" with something that is
intrinsically "out of band", incidentally, which is what Rob's "errors
are values" blog entry promotes instead. It is important to know the
distinction and make a decision accordingly - I doubt we can or even
wish to change that now.
Let me add that encouragement to terminate a function at arbitrary
points is also muddling things up: it multiplies the number of "normal
exits" - easier debugging, more difficult reading (subjectively,
though). It matters, because it characterises the Go philosophy more
accurately.
In summary, the Go Team needs to see the impact "try" will have on the
language and the community, which requires experimentation, probably
more of a social than a technical type. Let them proceed so they can
convince the community that the eventual outcome will originate from
the results of the experiment and not from their failure so far to
come up with something that satisfies our expectations.
It's in time like these that leadership gets tempted to throw in the
towel. At such times, bad decisions are easily seen as the only way
forward. Let's not let that happen here. For one, we need the
discussion - like it or not - more than we need the outcome (my
opinion, of course).
(I really feel there is an emotional vein running through this
discussion, one that has not yet been acknowledged - just shows we're
(mostly?) human; humans can overcome such obstacles. Go may not be
perfect, but it "is great" )

@lootch Thanks for your comment. There's definitively a social engineering aspect to all of this - we're proposing to extend Go in unfamiliar ways, and if it's the language you use day in and day out that is very concerning, perhaps even scary; after all it changes how one is supposed to "speak" in this language. You are absolutely right that there are a lot of emotions running through this discussion - I can't see how a purely technical exchange would collect so much feedback in so little time. As to the decision, it's still early days. I'm not the only decision maker here but I suspect we will stick to the process and let this run its course and decide how to proceed by the end of July.
Regarding the insurmountable issues with try: not to be facetious, but it seems to me that the existence of try is proof that these issues are not insurmountable :-). Yes, try has odd requirements and behavior. The design doc is explicit on this subject. I note that new and make require a first argument which is a type, followed by regular arguments. No Go function has such a signature. unsafe.Offsetof requires a struct field (!) as argument - talking about an unusual signature. recover is only meaningful inside a deferred function and possibly stops an ongoing return/panic - another odd context-dependent requirement and strange control-flow behavior. Virtually every single existing built-in has some "code smell", which is the very reason they are built-ins.
Regarding the claim that the try design flies in the face of Go's philosophy or that it is an aesthetic failure: Since the proposal passed muster with the Go team, including several of the original Go designers before we published it, I'm going to make the bold statement that it is ok. As long as Go has a goto statement I think we can't be feeling too smug about Go's aesthetics.
But let me repeat what I've said  elsewhere:

Please be assured that we have no intention to rush any new language features without taking the time to understand them well and make sure that they are solving real problems in real code. We will take the time needed to get this right, just as we have done in the past.

It may be petty to say this, but I think "last return argument of the
called function must be of type error" stretches your counterexamples
somewhat. But I do see your point and we have reached a stage where
nothing more appropriate is likely to be proposed in the near future.
 But I'm just repeating myself, in common with
many others.
Let me add just on more point: it is all too easy to treat criticism
as aimed at oneself or one's own side when it is in fact intended for
the subject matter, to help improving it. A lot of information has
flowed through these "pages" and a lot of it has indicated that the
fork in the road is going to be an awkward one, no matter what. I wish
you (and us all) the very best of possible outcomes. I'm sure my
sentiments reflect those of the majority of the participating
community.
Lucio De Re.
On 7/4/19, Robert Griesemer<EMAIL_ADDRESS>wrote:

@lootch Thanks for your comment. There's definitively a social engineering
aspect to all of this - we're proposing to extend Go in unfamiliar ways, and
if it's the language you use day in and day out that is very concerning,
perhaps even scary; after all it changes how one is supposed to "speak" in
this language. You are absolutely right that there are a lot of emotions
running through this discussion - I can't see how a purely technical
exchange would collect so much feedback in so little time. As to the
decision, it's still early days. I'm not the only decision maker here but I
suspect we will stick to the
process and let this run its
course and decide how to proceed by the end of July.
Regarding the insurmountable issues with try: not to be facetious, but it
seems to me that the existence of try is proof that these issues are not
insurmountable :-). Yes, try has odd requirements and behavior. The design
doc is explicit on this
subject.
I note that new and make require a first argument which is a type,
followed by regular arguments. No Go function has such a signature.
unsafe.Offsetof requires a struct field (!) as argument - talking about an
unusual signature. recover is only meaningful inside a deferred function
and possibly stops an ongoing return/panic - another odd context-dependent
requirement and strange control-flow behavior. Virtually every single
existing built-in has some "code smell", which is the very reason they are
built-ins.
Regarding the claim that the try design flies in the face of Go's
philosophy or that it is an aesthetic failure: Since the proposal passed
muster with the Go team, including several of the original Go designers
before we published it, I'm going to make the bold statement that it is ok.
As long as Go has a goto statement I think we can't be feeling too smug
about Go's aesthetics.
But let me repeat what I've said
elsewhere:

Please be assured that we have no intention to rush any new language
features without taking the time to understand them well and make sure
that they are solving real problems in real code. We will take the time
needed to get this right, just as we have done in the past.

--
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub:
https://github.com/golang/go/issues/32611#issuecomment-508345807

--
Lucio De Re
2 Piet Retief St
Kestell (Eastern Free State)
9860 South Africa
Ph.: +27 58 653 1433
Cell: +27 83 251 5824
FAX: +27 58 653 1435

@griesmer

@campoy try is just a macro, fashioned into a built-in function.

Then why not onErr macro instead? One that only checks for err != nil, then
if true executes return, goto or panic?

If we could write try in Go, one might write it and use it like any other
function we use to factor out shared code (one sort of can, using ugly hacks
with panic and defer, for specialized calls, but that's beside the
point). try doesn't introduce new syntax or new keywords; and since it
lives in the universe scope, it can be shadowed like any other name. As a
consequence, it won't affect any existing code.

It will badly affect all future code
[...]

But there is really a difference between a built-in function and a new
statement. Built-ins can easily be ignored (because they don't
interfere with existing code).

No they can NOT be ignored while reading and comprehending the code.
(And I personally am reading my own code ten times more often than
I write it. Not to mention other's code I am trying to dissect.)

With few exceptions (len, append), they can be skipped
when learning the language, and introduced on demand.

IMO, only the complex, real and imag can be introduced on demand.
All the rest must be understood, at least for their purpose and result, while onboarding
into a project. How one could be supposed to read Go code without knowing of
signature of the make, ehm?

In the spec they show up at the end. Several built-ins are not strictly
"needed" and one could write the same code by hand (append, copy,
complex come to mind) - these are here purely for convenience. try falls
into this category.

No, try does not fall into that category. Neither append, nor copy, nor make
have peculiar demands about other parts of the code nor they need augmenting
prose in the specs.

A statement cannot be ignored - it is either used or it must be avoided (in
the sense that we cannot have identifiers that collide with keywords of
statements). It must be learned by everybody for that reason. In the spec it
shows up prominently.

And thats good. We do expect all apprentices to learn that failures must be dealt with in clear.
[...]

because it can be used in an expression, something we can't do with on err.

Having try as a function allows for, if not encourages to, hard to notice
slips (pointed at #32437 discussion). I can add to this: how a debugger output
will look like to set my attention at a fifth wrap of the tryies oneliner matrioshka?
And how much effort will it demand from debugger authors?

Yet it comes at much less cost. It doesn't scream "you must use me for error
handling" in the language spec. It's just a little built-in for convenience

An the false (write time only) convenience of it will make it hard to
eradicate from the Go newcomers minds, so we will soon see a 20 cases
switch at the topmost defer then down the body single lines dense of
nesting try-parenthesis soup. LISPers will be happy, Gophers will not.

@campoy try is just a macro, fashioned into a built-in function.

onErr as a built-in macro will be yet more trivial to implement without endangering Go's purity:
OnerrStmt = "onErr" ( "return" | "goto" | "panic" )

Onerr macro executes a single terminating statement `return`, `goto`, or
`panic` if a variable named `err` is not `nil`. Otherwise its a noop.

(excuse me Lucio, its your words and my simplified version. We all are in quest for
the most gain from the least changes set ;)

In cases where the if err != nil test is combined with an initializer expression that sets the err variable in the local if scope, say:
if _, err := f(); err != nil {
   return ..., err
}

using on err will expose the err variable in the scope enclosing the if statement:
_, err := f()
on err return ..., err

Here are examples of such code. See lines 378ff.
This may be problematic.
try doesn't have this problem. That is, in cases like these, which are not uncommon, on err is strictly worse that try.

@griesemer

This may be problematic.
try doesn't have this problem. That is, in cases like these, which are not uncommon, on err is strictly worse than try, and also worse than if.

Yep, the OP version.
The "mine" macro version might not, if implemented as a subparse from the onErr token to the '\n' of its line.
_, err := f()
onErr return ..., err \n
//_1_ |   subparse     |
}

// is expanded to =>
//
if err != nil {
    // subparse
}
// =>
if err != nil {
    return ..., err
}

@griesemer Ok, you've made a case for "minor built-in". But I feel it's disingenuous to call it backward-compatible. It is, but only because it obfuscates existing code that uses a try identifier. IMO it's better to break code than obscure its meaning.
The essential point here is not that I've discovered a magic fix. It's that the Go team should pursue an alternative (or shelve the issue and revisit after generics), given the widespread and intense disapproval for try().
With on err I tried to come up with a general-purpose alternative to if ... { <stmt> }. It could be revised to be more special-purpose, as @ohir suggests.
v, ev := f()

catch <stmt>                // test last var in preceding assignment
catch (ev == io.EOF) <stmt> // test last var and boolean condition
catch (ep, ok := ev.(*os.PathError); ok) <stmt> // allow assignment preceding condition

I'm sure there's a solution to the problem of exposing the error variable to the rest of the function, as well.

But there is really a difference between a built-in function and a new statement. Built-ins can easily be ignored (because they don't interfere with existing code). With few exceptions (len, append), they can be skipped when learning the language, and introduced on demand. In the spec they show up at the end. Several built-ins are not strictly "needed" and one could write the same code by hand (append, copy, complex come to mind) - these are here purely for convenience. try falls into this category.
A statement cannot be ignored - it is either used or it must be avoided (in the sense that we cannot have identifiers that collide with keywords of statements). It must be learned by everybody for that reason. In the spec it shows up prominently.

@griesemer, that is a valid set of points.
That said, when it comes to learning about a try builtin vs. some statement-based variation, another set of questions is "how prominent would it be" and "how many words would it take to describe" in places like:

the official Go tour, and sites like https://gobyexample.com
intro Go tutorials, intro blogs, intro books, etc.

Setting aside for the moment the exact form a statement-based variation of try might take, one could certainly imagine that there is a statement-based variation of try that would end up being equally prominent in those places, and it could take roughly the same number of words to usefully introduce the concept and mechanism as a try builtin.
In other words, I suspect a builtin-based try would in practice end up being learned more-or-less just as soon for a new gopher as a statement-based try variation (given error handling is fairly central to how one writes Go), and one could imagine there exists a statement-based syntax that could be learned roughly as easily.
On your points about the spec -- one of the things people praise about Go is how the spec is very readable, and seasoned gophers often recommend new gophers take the time to read the spec... but even there, a "typical" new gopher likely reads several other introductory things prior to venturing into the spec.
In any event, thanks for taking the time to share your thinking as well as to engage on the different concerns and ideas that have surfaced from the broader community since the proposal was published.

Also, regarding a builtin vs keyword, there are separate concerns regarding different transition costs for community tools, and possibly the need to wait for modules to default to on to allow the Go language version to be controlled if a breaking change is introduced with a new keyword, etc.
I was not trying to rehash all the pros and cons for a keyword vs builtin, and was more just making some guesses around the perceived complexity of the result.

I've addressed @griesemer's feedback in the Critiques section of the issue. I added the catch variant described previously, and expanded on it to scope the error variable to the statement:
_ = f()
catch err, <stmt>
catch err, (err != io.EOF) <stmt>

Now I believe no arguments remain for try() aside from:
a) its use in expressions, which has been widely criticized, and
b) it's a minor built-in that you can ignore.

Now I believe no arguments remain for try() aside from . . . b) it's a minor built-in that you can ignore.

I don't really understand this point. From the perspective of a language user, there is no difference between a keyword and a builtin, except the way in which it is used. In either case, when they are learned is a function of their general applicability; it's never been my experience that e.g. builtins are more likely to be learned later or ignored, as I believe has been implied. More concretely, whether the error handling feature is a keyword or a builtin, it would certainly appear in the same place in a Go learning syllabus. Right? Could someone clarify?

it's never been my experience that e.g. builtins are more likely to be learned later or ignored

@peterbourgon I'm in favor of adopting try, or something close to be defined, but I agree that if try becomes a built-in, it will be used, and gophers will have to learn it sooner than later, as they do with the other built-ins. A built-in has advantages over a keyword (no grammar change, backward compatibility, future extensibility), but it can't be ignored in a public codebase. It can only be ignored in a private codebase.

@peterbourgon I think it's fair to say that a novice to Go will be able to program without try and do error handling - it's not something that needs to be learned to get going (it's what we do now, after all). But you're right that once they start reading other people's code, they will have to look it up. And yes, if try becomes common practice, it probably will be introduced in a syllabus right after explaining how to use if err != nil.
(We have a few built-ins that we don't strictly need: new can be done by taking the address of a variable, append and copy could be custom-written, complex I've already mentioned, and print and println are for convenience. try falls into a similar category in my mind; it adds convenience where it is applicable. I haven't heard the complaint that the presence of these "unnecessary" built-ins has made Go harder to learn due to the increased complexity.)

@networkimprov

I added the catch variant described previously, and expanded on it to scope the error variable to the statement:

With all due respect, all that additions and refinements morph your initial simple solution into something that will need no less cognitive load as try. IMO.

@griesemer

(We have a few built-ins that we don't strictly need: new can be done by taking the address of a variable, append and copy could be custom-written, complex I've already mentioned, and print and println are for convenience. try falls into a similar category in my mind; it adds convenience where it is applicable.

But yours try, while smart, makes writing convoluted paths convenient,  using magic that (except autodereferencing) so far has not been used in Go spec.

And yes, if try becomes common practice, it probably will be introduced in a syllabus right after explaining how to use if err != nil

if is if, boolean expressions are 101, then an apprentice will need to learn and remember that:
[note that this is a description of reasoning, not a manual entry]
try, while looks like a function call, is in fact not a try function call, but it is an invocation of a magic ~spell~ macro that will behave like a function call to the function given in try's parenthesis, if and only if that real call will return nil in its last return parameter of type error position. Otherwise, as for the last return parameter of called func not being nil, try magically will morph into a plain naked return ...never forget that the outermost, and outermost only, try incantation cuts off the last return parameter (usually err)! .
Try in its current shape adds too much convenience for too hefty price tag. Readability and simplicity-wise. Make it a statement at least, please, so it will have to occupy its own line.
It is the try's ability to nest that concerns. Frankly, I know I personally would be tempted to abuse it, then curse on myself later.

It is the try's ability to nest that concerns. Frankly, I know I personally would be tempted to abuse it, then curse on myself later.

This! It's precisely the same temptation as the ternary operator proposals that the Go team has repeatedly quashed (rightly, imo.)

@ohir Concerns around nesting is not new feedback, and again, a go/analysis check for nested trys or multiple trys on the same line seems entirely straightforward. And I suspect there would be support for getting it into vet as a default check.
@networkimprov I think this proposal needs to be specific about what exactly it's proposing. The proposal seems to have a wide range of possible changes to the language, and it's making it hard to evaluate. The specific keyword doesn't really matter at all, but the exact semantics of what you're proposing does. For instance, any thought like "is there implicit dataflow between an unnamed variable assignment and the following statement?" always has an answer of "maybe", as there are some things in your proposal that imply yes and others that imply no. Same for a foundational question like "does the keyword only apply to values of type error?".

I added alternatives to address feedback; I didn't drop anything so as not to erase the context of early discussion. I'm only aware of one "implicit dataflow from an unnamed variable," as a way to scope an error variable to the stmt. And I stated that variable tests are against zero values.
The proposal needs further refinement, but there's no point without help from the Go team, and it looks like we'll get that only if try() is abandoned after it's been prototyped. They haven't stated any willingness to include an alternative to try() in pre-release 1.14, sadly.

I'm not sure what kind of help you are looking for from the Go team, or what further refinements are appropriate.  You've gotten comments from at least three members of the Go team here.
As I suggested above, I personally am not in favor of this, as it adds a new keyword, and a new kind of statement syntax, and a new kind of expression, all to save the boilerplate of a comparison expression.  Saving boilerplate is good but adding three new ideas to the language is a heavy cost.
To be very clear, I am not trying to say "therefore we should implement the try proposal."  I am saying that this proposal, viewed by itself, does not, in my personal opinion, provide a benefit that exceeds the cost.  And I want to stress that the cost of a new kind of statement syntax and a new kind of expression is a high cost for a language like Go that aims to be orthogonal and to have a minimal number of concepts.  And, again, to be very clear, it is perfectly fair to argue that the try proposal is also not orthogonal, but it does not follow that we should adopt this proposal.

I just wanted to point out that the discussion here has been very helpful in understanding some of the conflicts between the Go team and the community, in particular around builtin functions vs new keywords.
I'm curious, is it possible to restrict the use of a builtin (like try) to only ever be used as a statement? Presumably this would just be a tools setting, would such a setting ever make it into the standard Go tools as default?

On 7/6/19, Robert Griesemer<EMAIL_ADDRESS>wrote:

[ ... ]
(We have a few built-ins that we don't strictly need: new can be done by
taking the address of a variable, append and copy could be
custom-written, complex I've already mentioned, and print and println
are for convenience. try falls into a similar category in my mind; it adds
convenience where it is applicable. I haven't heard the complaint that the
presence of these "unnecessary" built-ins has made Go harder to learn due to
the increased complexity.)

Please slow down a second here.
I recall Rob Pike mentioning that "new" was more accidental than
intentional. Clearly, append and copy are "generics" in some sense,
print and println are debug functions and would probably be disabled
if that was in any way possible in Go, I'm not sure about complex, it
seems like a type that begs to be part of a bigger project to add a
calculator as a built-in interpreter (APL in the way Tcl was intended?
expr in the Bourne shell?) and totally drop arithmetic operations from
the language (don't take this last suggestion seriously, please, I am
not entirely insane :-) ).
Knowing what these built-ins exist is necessary, yes, but none of the
are mysterious or magic and, right now, still optional.
Lucio.

@Qhesz I think the place for that question is in the try proposal #32437 where a LOT of ppl have requested exactly that (and maybe delete your post above).
The focus here is simplification of single-statement error handlers.

@ianlancetaylor there are two classes of cost:

the cost to the spec, which you elaborated above for this proposal.
the cost to users, which the community has detailed at length for the try proposal.

The costs of try() and on err to the spec are roughly the same.
The costs of the two proposals to the users are radically different.
The cost to users -- i.e. reduction of productivity -- is far more important than the cost to the spec.

@networkimprov

The costs of try() and on err to the spec are roughly the same.

Unfortunately these are not equal. Cost of adding a new keyword or syntax element is enormous and magnitudes higher than adding a built-in. While adding a built-in means changes to the compiler only,
adding a keyword (even expanded to the simple ast node or two as mine's #32946) intails an obligation to change (amend) all tools, and it extends to the third-party tools like linters and debuggers.
New keyword means that all these tools, including many used in the CI chain, may stop working.

@networkimprov Thanks for the comment.  However, I don't agree that it is possible to separate cost to the spec and cost to users.  If the spec is more complicated, then it is harder for people to learn the language, and there is more for readers and writers to remember.  Simplicity is a significant goal of Go, based on the assumption that keeping the spec simple means keeping the language simple means keeping it simple for programmers to learn and to use.  If on err requires a different kind of expression, then we have to explain to all users of Go "this is what an expression looks like, except that you have to remember that in an on err statement there are various restrictions."  That is a cost to the spec and it is also a cost to users.
And, again, I am not talking about try.  I am talking about on err.  Each proposal must stand and fall on its own.  It does not make sense to say "try is bad therefore we should adopt on err."  Perhaps try is bad, in which case we should not adopt it.  But we shouldn't take the arguments about try and use them to say that we should adopt on err.  They are two separate and independent proposals.  The  only connection between them is that it is very unlikely that we would adopt both.

@ianlancetaylor, I'm afraid you've missed my point. The community is at the barricades about try() because we believe it would damage our code and/or the ecosystem of code we depend on, and thereby reduce our productivity and quality of product. That's the "cost to users" I refer to. Perhaps I should call it the "cost to the ecosystem."
This proposal does no such damage.
The "cost to the spec" as I define it includes the need to "explain to all users of Go" that a feature adds unique concepts to the language. As I've stated, the cost to the spec should be a far smaller concern than the cost to the ecosystem.
As this proposal has virtually no cost to the ecosystem, and roughly equal cost to the spec as try(), there's really no contest.
Re "this is what an expression looks like, except ... in an on err statement," I addressed that with
catch <stmt> in Critiques no. 1.

@networkimprov

This proposal does no such damage.
As this proposal has virtually no cost to the ecosystem, and roughly equal cost to the spec as try(), there's really no contest.

You provide no evidence for any of these assertions.
The last one, in particular, makes no sense to me. try is a single built-in function which can be described straightforwardly in terms of if and return, and requires no changes to the language grammar. This proposal, on the other hand, introduces two new statements, one of which, on err, has a somewhat novel syntax for Go, as well as a new predeclared type caller. It gets even more complex if one incorporates some of the possible extensions you also propose.

There's abundant testimony to the damage try() would do in #32437. This proposal presumes the testimony is valid, and avoids those problems. I've stated that it needs refinement, and made a second pass in Critiques nos. 1 & 2. I hope others will offer ideas to improve it.
If you prefer try(), be of good cheer, it's coming in pre-release 1.14.

@networkimprov You (apparently) don't like try, and you do like this proposal.
It seems like you're implying that everyone who doesn't like try must therefore like this proposal.
But this is not necessarily true. So it seems premature to start speaking for the community with "we", and stating outright that your proposal "avoids those problems" (e.g. one of the concerns was where to place a breakpoint when debugging, something unaddressed by this proposal).
In any case, I'm going to say again: this proposal seems too vague. A proposal generally proposes a specific set of changes to the language. Above, in a response to Ian, you say "I addressed that with catch  in Critiques no. 1". There is 10x the content in your proposal referring to "on err" than content referring to "catch", but this reply to Ian seems to imply that "catch" is the actual proposal you are making. It is fine to record old information about the proposal for context, but it seems odd to have the real proposal dwarfed by historical information that doesn't apply anymore.
One option that both records the history, and keeps the proposal specific would be to record old versions in a separate place (e.g. a gist), update the proposal to be the actual set of changes you are proposing, and linking to the old versions in the gist.
So, assuming your concrete proposal is the content of Critiques 1 and 2: I think you are saying that the "catch" statement must be immediately after an assignment statement, it checks that the last assigned variable (which can be _) has the zero value of its type, and if it doesn't, then executes the catch statement's right-hand-side statement.  This RHS statement must be from a restricted set of statements (list TBD). Is that accurate?
If so, some thoughts:
1] I don't think the _ solves the scoping issue, by the way. For instance, in this code:
// Before
if err := foo(); err != nil {
  return "", err
}

// After
_ := foo()
catch return "", ???

Since I used _ to bind the error variable, I no longer have it available to propagate upwards.
2] It seems odd for a catch statement to operate on arbitrary types. E.g. catch can check for non-empty strings, non-zero floats, non-empty structs, non-nil slices. That all seems unnecessary. IIRC, one of your blogposts had claimed that this property was desirable for checking errno, but first of all, errno checking seems relatively rare to me, and secondly, most of the functions in the syscall package return either an error, or a syscall.Errno struct which implements error.

This is a work in progress; I'm sorry if that annoys anyone.

There is 10x the content in your proposal referring to "on err" than content referring to "catch"

on err and catch have the same meaning: if <variable> != zero_value.

This RHS statement must be from a restricted set of statements (list TBD). Is that accurate?

From the text: "supports any single-statement action..." Specifics further explains that certain Go constructs are not single statements, e.g. func(){...}()

I don't think the _ solves the scoping issue

In Critiques no. 2 I suggest naming the caught variable: catch err, <stmt>. It's just an idea; alternatives welcome.

It seems odd for a catch statement to operate on arbitrary types.

Many C libraries return errno-like values. But we could restrict catch to type error for the sake of safety or clarity. Thank you for reading my blog post!

one of the concerns was where to place a breakpoint when debugging

A breakpoint on the catch line would trigger only if <stmt> will run.

It seems like you're implying that everyone who doesn't like try must therefore like this proposal.

Hardly; most people who dislike try() apparently want no change whatsoever! This is a compromise.

Thanks for the very detailed explanation, @griesemer!

@networkimprov For the record, I do not accept your distinction between "cost to users" or "cost to the ecosystem" and "cost to the spec."  I do not find that to be a useful line to draw.
As I've said multiple times in this issue, my comments above are specifically about this proposal.  You keep bringing up the try proposal, but my comments above are not about the try proposal.  I'm honestly not sure, but I think you are making an argument that is something like 1) we must do something about errors; 2) the try proposal is bad; 3) this proposal is better than the try proposal; 4) therefore, we should accept this proposal.  If that is the argument you are making, I don't agree with it.
I would say, instead, that I do not think this proposal is a good idea, and I do not think we should adopt it.  I've explained my reasoning above.
We can then, separately, discuss the try proposal.  It may very well be that the try proposal is bad and that we should not accept it.  But even if we agree on that, even if we agree that we should not accept the try proposal, I do not think that we should therefore adopt this proposal.
If you reply to this comment, I encourage you to make an effort to not mention the try proposal.  It simply isn't relevant to the discussion of this proposal.
With regard to catch rather than on err:

the form catch <stmt> can apparently only appear after an assignment statement, a form of restriction that applies to no other statement in Go.  It apparently implicitly refers to a variable set or defined in the previous statement, a form of implicit reference that occurs in no other statement in Go.
the other forms of catch appear to me to be identical to if, except that the curly braces are omitted.  That seems fairly minor.

I am speaking only for myself here.

@ianlancetaylor based on your comments here, I gather that you personally favor the request to "leave if err != nil alone". Can you confirm?

catch <stmt> can apparently only appear after an assignment statement

Because it's like an else. Other similar restrictions include:
a) we can't write for x {...} else {...}.
b) func f() {...} cannot appear within a function.
c) default: ... has no meaning outside switch and select.

It apparently implicitly refers to a variable set or defined in the previous statement

An else implicitly refers to the expression in its if. A default implicitly refers to all cases in its switch.

the other forms of catch appear to me to be identical to if

No, they make implicit variable != zero_value tests, as with catch <stmt>.

you are making an argument that is something like 1) we must do something about errors

The Go team asserts that surveys show that error handling is widely considered painful. (Tho that's apparently contradicted by #32825.) Also, I have stated that we should see a generics solution land before any error handling features.

I am speaking only for myself here.

In this forum where you regularly speak for the Go team, I don't believe anyone would absorb that claim.

@ianlancetaylor based on your comments here, I gather that you personally favor the request to "leave if err != nil alone". Can you confirm?

I guess I'm not sure where that comes from.  Personally, I think that we should try to do something about error handling, given how often it comes up as an issue for people learning and using Go.  When people makes jokes about a language pattern (e.g., https://images.app.goo.gl/khYRQQUSYaGCEiwV9) they are pointing to a deficiency in the language.

catch  can apparently only appear after an assignment statement

Because it's like an else. Other similar restrictions include:

Note that else can not appear as a statement by itself.  You can't even write
if x {
    fmt.Println("x")
}
else {
    fmt.Println("not x")
}

An else clause is intrinsically part of an if statement.  So if catch is like else, it seems to me that there should be some direct syntactic connection between the assignment statement and the catch clause.  I'm not sure I like that either, but I think it would be better than a standalone statement that is not really standalone.
The same applies to your default example; it is syntactically associated with a switch statement.
The restriction on writing func f() {} inside a function seems to me like a different kind of thing.  It is not an example of something added, but rather of something prohibited.  (I think the reason we don't permit func f() {} inside a function is that we could never decide on the scope of the identifier f: is it visible inside the body of f?  Is it visible to other nested functions that appear before f?)

the other forms of catch appear to me to be identical to if

No, they make implicit variable != zero_value tests, as with catch .

Both examples are testing an implicitly defined variable err against a non-nil value.  If there an implicit != zero test, I'm not sure where it applies.  But, even accepting that, that is just saving a few characters over an if statement.

I am speaking only for myself here.

In this forum where you regularly speak for the Go team, I don't believe anyone would absorb that claim.

I only occasionally speak for the Go team, but the fact that I occasionally do is why in a comment like this I am careful to explicitly state that I am speaking only for myself.  I can't control whether people absorb that, the best I can do is try to be clear and honest.
Here again, I am speaking only for myself.

Personally, I think that we should try to do something about error handling

Are you discussing this because you see something in this proposal worth developing? You and the other team leaders aren't commenting in other try() alternatives that I'm aware of. (I'd rather not invest in a moot debate :-)

I only occasionally speak for the Go team

I had the impression, and I believe it's common, that you and the other team leaders generally speak for the team when you comment in the official forums.

Are you discussing this because you see something in this proposal worth developing? You and the other team leaders aren't commenting in other try() alternatives that I'm aware of. (I'd rather not invest in a moot debate :-)

I'm discussing this because you explicitly said, in https://github.com/golang/go/issues/32611#issuecomment-508959846

The proposal needs further refinement, but there's no point without help from the Go team, and it looks like we'll get that only if try() is abandoned after it's been prototyped. They haven't stated any willingness to include an alternative to try() in pre-release 1.14, sadly.

I felt that that statement was unfair, given that at least three members of the Go team had already commented on the proposal, and given that we try very hard to stay open to input at all times.
Also, you brought up the proposal on golang-nuts saying that it may have traction, although the downvotes appear to outnumber the upvotes at least at this time.
I see serious problems with this specific proposal, as I've expressed above.  I've tried to point out problems I see in a number of other proposals as well.

I had the impression, and I believe it's common, that you and the other team leaders generally speak for the team when you comment in the official forums.

That turns out not to be the case.  I don't think we could possibly keep up with the discussion if we had to get together and formulate an agreed-upon response before each reply.  We're not even all in the same timezone.  And I'm sure there have been cases where we have publicly disagreed with each other.

If my adjustments & clarifications haven't affected your distaste for this idea, then I'll bow out of the debate.
However I believe this proposal fulfills its goals of obvious, consistent, terse error handling. If the Go team endorsed it, I believe the community would embrace it.
I've accommodated all objections to date, except: "there should be some direct syntactic connection between the assignment ... and the catch ..." That would add boilerplate, but not clarity.
IMO it's a flaw that the compiler...
permits: if t {...} else {...} // 1 line
but not: if t {...} \n else {...} // 2 lines
Formatting is the precinct of go fmt (which I don't use, fwiw).

I've tried to point out problems I see in a number of other proposals as well.

I don't recall you documenting problems with try(). If you see any, why haven't you made them known?

The proposal seems to be mutating a bit, so I'm not entirely clear on precisely what we are talking about.  But if we are talking about check, I don't think you'e accommodated the objection that it removes very little boilerplate compared to if.  Which is also a problem with on err.  All language changes are costly, and those that add a new keyword are especially costly.  We need a corresponding benefit.  I don't see it here.

I don't recall you documenting problems with try(). If you see any, why haven't you made them known?

Because I (and others) talked the proposal through with @griesemer before he published it.  And, of course, it's loosely based on the design draft that @mpvl published last year, which had plenty of commentary from plenty of people.  So the issues I am most concerned about have already been addressed.
Again, speaking only for myself.

So the issues I am most concerned about have already been addressed.

Perhaps so, but it would still benefit the debate for Go team members to state publicly whatever personal objections they have. I know a few hundred people who'd like to hear them :-)

I don't think you'e accommodated the objection that it removes very little boilerplate compared to if

We could define return err as the default action, tho I think it's better to be explicit:
err := f()
catch ; // semicolon to clarify that handler wasn't omitted by mistake?

If the members of the Go team have personal objections to the try proposal, they will state them.

As discussed above in several different comments, this proposal adds language complexity while removing little of the error handling boilerplate.  Given that there is little enthusiasm for eliminating error handling boilerplate alone, the cost of this proposal is simply not worth the marginal benefit that it provides.  This proposal is basically a different way of writing an if statement.
-- writing for @golang/proposal-review

Forgive me if this is the wrong place for this feedback.

Given that there is little enthusiasm for eliminating error handling boilerplate alone

I guess this may be getting at what Robert wrote in the closing comment to the try proposal, when he noted that it’s worth clarifying what the problem we’re trying to solve actually is. But I challenge this summary: in my opinion it is precisely and only the boilerplate that should be reduced, the current semantics—error handling as separate statements/blocks directly adjacent to the error-generating code—is important and foundational and should not be changed.

@peterbourgon I don't think I agree with what you say but I doubt this is the best place for this discussion.  In any case I don't think that discussion affects the decision on this issue.  No matter what you consider to be boilerplate, this proposal doesn't remove enough of it to be worth the cost.

I don’t agree that this proposal doesn’t remove enough boilerplate, but that is of course subjective. I would love to have a more productive conversation about this; if the time and place for that conversation becomes apparent, please keep me in the loop.

My analysis of the boilerplate for this specific proposal can be seen at https://github.com/golang/go/issues/32611#issuecomment-507867010 .

I think option 3. from networkimprov has been underestimated (to quote):
"go fmt could just allow single-line if statements:
Would it also allow single-line case, for, else, var () ? I'd like them all, please ;-)
The Go team has turned aside many requests for single-line error checks."
If gofmt were to allow single-statement if-statements for err != nil to appear on a single line,
visual clutter would be greatly reduced, without any change to the Go language.
I come from C and I greatly value the enormous effort and experience that has gone into making
Go simple to understand and use. I also appreciate gofmt which removes a lot of trivial formatting
decision making.
A 3-line boilerplate handball up the stack of an error from a called function is not the end of the
world for me or anyone else.
But ... in libraries I wrote in C, I returned an error value from almost every function and handballed it up the
stack with a single line if statement.
Where an error needed to be originated, or a returned error needed to be decorated, I did that on
multiple lines.
There was no error handling clutter, except where it counted: new error generation, and decoration.
Error generation, decoration and handballing was clear and uncluttered. And that was achieved by
the C equivalent of:
if err != nil { return err }

@urban-wombat You already opened #33113 for that.  I suggest that if you want to mention it on other issues that you point to that one.  That seems better than scattering discussion over a range of different issues.  Thanks.

@peterbourgon I re-read your earlier rationale, and I still feel that this specific change doesn't make enough of a difference to make it worth changing the language.  This is particularly true given the additional  non-orthogonal concepts that this change implies: a new restricted form of expressions and a new statement syntax.

Hi  @peterbourgon, some quick comments.
This current proposal is fairly broad, including the proposal itself has a fair number of permutations
Sometimes, "broader" is good because it means the solution is more general. In other cases, "broader" increases the cost of a change, or increases overlap with existing alternatives.
For example, as originally written, as far as I followed, any zero value is supported and it is not specific to error types, which would mean something like this is supported under the original proposal here:
someMap := getMap()
on someMap, goto label

In that case, that is a broader capability than strictly targeting error handling (which in turn requires a judgement call as to whether or not it is good to be broader in that way).
I think there is a narrower form of this proposal that is closer to what I think I might have seen you sketch roughly as:
a, err := f()
on err, errors.Annotatef(err, "message")

In any event, because this proposal has a fair number of permutations, in some cases it has been hard at least for me to understand which permutation a specific comment is addressing.
(Finally, I am speaking for myself as a more-or-less random gopher from the broader community. In other words, just to be explicit, I am not member of the core Go team).

There is no need to continue this discussion.
If you read carefully, it's clear that the Go team was only interested in:
a) zero lines of boilerplate (this proposal specifies 1 line), and
b) no changes to assignment LHS (as in #32500).
IOW, only an expression like check or try() is acceptable to the Go team. That is clearly a non-starter with the community, so we are at an impasse. We should therefore let the Go team focus on other work, e.g. generics.
Thanks for everyone's interest,
Liam

It’s clear that the Go team was only interested in:
a) zero lines of boilerplate (this proposal specifies 1 line), and
b) no changes to assignment LHS (as in #32500).

This should be confirmed by the Go team and not merely assumed. (This is also what I was driving at with my set of scoping questions here.)

Speaking purely personally, I don't agree with @networkimprov 's comment at https://github.com/golang/go/issues/32611#issuecomment-512933966 .  We don't have specific requirements of that sort.  If we did, we would say them.
We do our best to judge each proposal on its own merits.  Every language change has costs and benefits.  I want to stress, again, that this specific proposal introduced new concepts into the language, and that is a cost.  We need a benefit that is worth that cost, and in the opinion of the proposal review team the benefit of this specific proposal was not worth the cost of this specific proposal.
To conclude from that that the Go team is only interested in "zero lines of boilerplate" or "no changes to assignment LHS" is to misunderstand what we are saying.  We are weighing costs and benefits.  We are not saying that only certain kinds of changes are acceptable.  We are saying that the benefits of a change must outweigh the costs of a change.

I don't believe you're misleading us, but I stand by my assessment of the Go team's interests. You write as if "costs" and "benefits" were objective measurements. They are subjective in this case, and therefore influenced by preferences which one may not be fully aware of.

You're right of course that costs and benefits are somewhat subjective.  As has been said, Go is an opinionated language.
That said I think that you are simply mistaken in the conclusions that you are drawing.  I think it's clear that Go has considerable tolerance for boilerplate.  I don't see how it's possible to conclude that the Go team would only accept a proposal that reduces boilerplate down to zero lines.
I agree that additional syntax on the left hand side of an assignment statement is a bigger lift, since there is nothing like that in Go today.  Currently the left hand side of an assignment must be addressable, be a map index expression, or be the special identifier _.  In those three cases assignment is a fairly straightforward operation: just copy or discard a value.  To change the left hand side of an assignment statement to cause some action other than assignment to occur is a big cost and requires a big benefit.
But to say that any of these ideas are ruled out a priori is to misunderstand the nature of costs and benefits.  Even if costs and benefits are subjective, which to some extent they are, it doesn't mean that the costs can not be incurred.  It just means that they need a corresponding benefit.
Clearly there are some changes that will never be made to Go.  For example, we will never break significant amounts of existing Go code; that is a cost that is so high that it's impossible to imagine a corresponding benefit.  But I don't see why the kinds of changes we are talking about here rise to that level.
I could very well be wrong, but it seems to me that in these discussions you persistently underestimate the costs of a language change.  That underestimation, if real, may lead you to conclude that the Go team must not see the benefits of the change.  I encourage you to seriously consider that perhaps we do see at least some of the benefits, but that we judge the costs differently than you do.
Above you tried to separate cost to the spec, cost to the users, and cost to the tooling.  That is very different from the way that I view the costs of language changes.  The only cost that matters is the cost of understanding the language.  Every special case in the language (and the language has far too many special cases already) is a cost.  The goal is a language that is simple and orthogonal.  Every concept in the language should ideally interact with every other concept clearly and simply.  When certain kinds of expressions that can only be used in one place, when we add certain kinds of statement syntax that can only be used with one statement, those are big costs.
As you know, the discussion of the try proposal stressed that it was a builtin function that changed no other aspect of the language.  That is another way of saying that cost of try was limited to understanding one more special case, a special case akin to the existing special cases of the builtin functions panic and recover.  There was no new syntax, no new constraints, no affect on general language orthogonality.  Those were important points in limiting the cost of try.  Of course it still had costs, and the heated discussion was in itself a significant cost, and in the end we agreed that those costs were too high for the benefit of try.

A belief that "the only cost that matters is the cost of understanding the language" may guide you into future community resistance, because we are all acutely aware of what I called the "cost to the users/ecoysystem" https://github.com/golang/go/issues/32611#issuecomment-509025988.
I based my assessment above on statements by Robert and Russ in other discussions. And "zero new statements" is an equivalent criterion to "zero boilerplate lines". Re cost of a language change, the Go team was first to propose such a thing: check/handle.
That's all I'll say on the matter, and you'll be relieved to hear that I have no strong opinions on generics :-)

I continue to disagree that "cost to the users/ecosystem" is distinct from what I am considering.
I want to make clear that I did not say or imply anything like "zero new statements."

Thanks ianlancetaylor, point taken.
See my further comment elaborating on proposal #33113 and especially the Go Playground code samples:-

Current gofmt formatting
Proposed gofmt formatting

The case for the proposed gofmt change seems even stronger when named
outputs are used. Here's a variant of urban-wombat's second Go Playground
example.
https://play.golang.org/p/_X_RTEKD1py
On Thu, Jul 18, 2019 at 11:06 PM urban-wombat<EMAIL_ADDRESS>wrote:

Thanks ianlancetaylor https://github.com/ianlancetaylor, point taken.
See my further comment elaborating on proposal #33113
https://github.com/golang/go/issues/33113 and especially the Go
Playground code samples:-

Current gofmt formatting https://play.golang.org/p/3vUlTc1TGwj
Proposed gofmt formatting https://play.golang.org/p/zsWYS1FB11M

—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/golang/go/issues/32611?email_source=notifications&email_token=ABTDSJNBIWHMOPL737K7OHLQAEVUPA5CNFSM4HYAP3Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2KNYIY#issuecomment-513072163,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABTDSJNJJUASTCSXFYQBTMTQAEVUPANCNFSM4HYAP3ZQ
.

May I impose on the last two commenters to re-post their comments on #33113 and delete the copies above? Thanks.

Let's not do it then
On Fri, 19 Jul 2019, 13:48 Michael-F-Ellis<EMAIL_ADDRESS>wrote:

@Liam Doesn't seem worth the effort since #33113
https://github.com/golang/go/issues/33113 was summarily closed.
On Fri, Jul 19, 2019 at 8:34 AM Liam<EMAIL_ADDRESS>wrote:

May I impose on the last two commenters to re-post their comments on
#33113 https://github.com/golang/go/issues/33113 and delete the copies
above? Thanks.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<
https://github.com/golang/go/issues/32611?email_source=notifications&email_token=ABTDSJMDPU7ULTFI3T6HO53QAGYHFA5CNFSM4HYAP3Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2LPPWA#issuecomment-513210328
,
or mute the thread
<
https://github.com/notifications/unsubscribe-auth/ABTDSJOXWEINKWNNSK3U77TQAGYHFANCNFSM4HYAP3ZQ
.

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/golang/go/issues/32611?email_source=notifications&email_token=AAAGRFC7T7WTIC6CI3YHS5TQAGZ2DA5CNFSM4HYAP3Z2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOD2LQPZY#issuecomment-513214439,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAAGRFEANUH6V3QBKX2GD3DQAGZ2DANCNFSM4HYAP3ZQ
.


Reverse migrations for wagtail

Allow migrations to be reversed.
#2072

Okay, so before you couldn't do this, and now you can :)
python manage.py migrate  # Initial migration
python manage.py migrate wagtailcore zero  # Undo all migrations
python manage.py migrate  # Re-run migrations

Great work, thanks!

Temporarily reverted until I can figure out what's up with the travis build


Low Throughput

Hi,
I'm not sure if this is the right spot for this question. I was hoping for some sort of slack channel or gitter or something.
I created a benchmark because I thought this might cause a speed up, but to my surprise I couldn't get much performance boost. To be fair: I'm completely new to observables and undertow and postgres 😄 .
Is there any supporting evidence that this is actually faster than jdbc? or is it a per use case kind of thing?
My code is at async-postgres-benchmark and specifically QueriesAsyncPostgresqlGetHandler.
Thanks!

There's a common misconception that async (non-blocking really) is "faster", when in reality, you'll often see slightly increased latency.
Non-blocking behavior increases the amount of load an application can handle, which means it will perform better under load than the equivalent blocking program.

I benchmarked this project before and after RxJava1 was introduced. Before it was just simple callback.
The RxJava1 overhead slowed down a simple select 1 operation by 30%. Hopefully update to RxJava2 would give some of that lost performance back.
Also the official postgres jdbc driver has lots of optimizations that are not ported to this driver, most notably the support for binary encoding of values.

IMO, it would be preferable to get rid of the RxJava dependency altogether.

Hi @nilskp and @gmokki
I'm not sure how my benchmark is measuring latency. I thought I understood that with async you trade off some latency for increased peak throughput. Please correct if this is false.
My question/comment was on why every measurement I tried is worse compared to the serial option. It's hard to find what exactly is gained with this project.


GitHub Action configuration issue.

GitHub vars context variables cannot be referenced from GitHub Actions.  So, I had to pass them as inputs to the GitHub Action from the deploy.yml and undeploy.yml workflows.


Reduce docker image size

This PR changes the base image to be cgr.dev/chainguard/glibc-dynamic:latest
Image size before the change: 172MB
Image size after the change: 23.8MB

We have set dependency requirements for the runtime image, maybe looking to build our own using the ChainGuard image as a guide would be better? Then we'd at least be in control of dependency updates and publish schedules & versioning.

@pellared @MrAlias
This is ready for another review.
Changed from the Chainguard image to Google distroless and used the sha256 digest as version

For reference, I think this is the repository the images are generated from: https://github.com/GoogleContainerTools/distroless

It looks like there are support timelines: https://github.com/GoogleContainerTools/distroless/blob/main/SUPPORT_POLICY.md

Docs:

Image Contents
This image contains a minimal Linux, glibc-based system. It is intended for use directly by "mostly-statically compiled" languages like Go, Rust or D.
Statically compiled applications (Go) that do not require libc can use the gcr.io/distroless/static image, which contains:

ca-certificates
A /etc/passwd entry for a root user
A /tmp directory
tzdata

Most other applications (and Go apps that require libc/cgo) should start with gcr.io/distroless/base, which contains all
of the packages in gcr.io/distroless/static, and

glibc
libssl
openssl


Server stuck @ start if run with SBATCH / srun

Hello,
I am trying to run your code for distributed python.
When I run it "manually" everything goes fine (the server starts and I can than connect the clients to it).
However the server never starts when I try to launch the whole thing via SBATCH / srun. I can see the python script starting, it reach the manager.start() line (a print added to the previous line is printed) but never goes to the following (I have no error message, but the print of the following line is never displayed and the clients cannot connect to the server).
https://github.com/eliben/code-for-blog/blob/27c13c32832792789822675bb5c08a7add655045/2012/parallel_python_multiprocessing/distributed_factor.py#L80
I have also tried to log into the nodes and then run the script "manually" from there: in that case everything is OK, so it is really linked to how srun launches the python script... do you have any idea of what can go wrong here?
Thanks in advance.

I'm not really familiar with SBATCH / srun, so I'm not sure I can help here. This is also fairly old code that I haven't been working with in quite a while

Thanks for replying.
I run some more tests and even if I still have some weird and unexpected results, I found out that I can launch the server in the sbatch script without the srun command, which make the server to properly work. The clients can be launched by srun so that they are distributed on the other nodes.


Node.js  Community Committee Meeting 2020-09-17

Time
UTC Thu 17-Sep-2020 16:00 (04:00 PM):

Timezone
Date/Time

US / Pacific
Thu 17-Sep-2020 09:00 (09:00 AM)

US / Mountain
Thu 17-Sep-2020 10:00 (10:00 AM)

US / Central
Thu 17-Sep-2020 11:00 (11:00 AM)

US / Eastern
Thu 17-Sep-2020 12:00 (12:00 PM)

EU / Western
Thu 17-Sep-2020 17:00 (05:00 PM)

EU / Central
Thu 17-Sep-2020 18:00 (06:00 PM)

EU / Eastern
Thu 17-Sep-2020 19:00 (07:00 PM)

Moscow
Thu 17-Sep-2020 19:00 (07:00 PM)

Chennai
Thu 17-Sep-2020 21:30 (09:30 PM)

Hangzhou
Fri 18-Sep-2020 00:00 (12:00 AM)

Tokyo
Fri 18-Sep-2020 01:00 (01:00 AM)

Sydney
Fri 18-Sep-2020 02:00 (02:00 AM)

Or in your local time:

https://www.timeanddate.com/worldclock/fixedtime.html?msg=Node.js+Foundation+Community Committee+Meeting+2020-09-17&iso=20200917T1600
or https://www.wolframalpha.com/input/?i=04PM+UTC%2C+Sep+17%2C+2020+in+local+time

Links

Minutes Google Doc: https://docs.google.com/document/d/1XvnRhRg-sMb5OWzdCbNu-farCvjhs5YPhGaQ5BoAJNo/edit

Agenda
Extracted from cc-agenda labelled issues and pull requests from the nodejs org prior to the meeting.
Invited

CommComm Members: @nodejs/community-committee

Observers/Guests
Feel free to follow along on the YouTube live stream, or attend meeting as a guest
by calling in to Zoom, using the links below. If you will be attending as a guest,
please comment on this issue to let us know you'll be joining.
Notes
The agenda comes from issues labelled with cc-agenda across all of the repositories in the nodejs org. Please label any additional issues that should be on the agenda before the meeting starts.
Joining the meeting

Link for participants: https://zoom.us/j/523381536
For those who just want to watch: https://www.youtube.com/channel/UCQPYJluYC_sn_Qz_XE-YbTQ

Invitees
Please use the following emoji reactions in this post to indicate your
availability.

:+1: - Attending
:-1: - Not attending
:confused: - Not sure yet

@joesepi will be running this today since I'll be OOO 👍🏻

Also just a tiny note: it'd be rad if someone could PR in the minutes for all the open meeting issues.


Error at responses

You have an small error with response for mailchimp. In your code
  'The domain portion of the email address is invalid (the portion after the @: )'    : 3,

and answer from mailchimp
 'The domain portion of the email address is invalid (the portion after the @: mail)'    : 3,

and translates don't work for 3rd variant.

This should be addressed in the 2.0 branch. Please try it out and see if it works for you.