top | item 20454966

Declined Proposal: A built-in Go error check function, “try”

474 points| robfig | 6 years ago |github.com | reply

408 comments

order
[+] wybiral|6 years ago|reply
This hits at something fundamental about Go, which is what I like the most about it...

It's a language intended to have few primitives with an emphasis on code being transparent and errors being values, requiring you to think about what they might be at each point as you're forced to carry them up the chain.

Do I particularly like managing errors that way? No, but I do think that it improves the transparency and quality of a lot of Go projects.

The same goes with the Go ecosystem and tools. You might not like how gofmt forces your code or the documentation conventions used by golint but the fact that we all use the same convention and documentation is awesome and it's what allows things like godoc.org. I think the proverb is "gofmt's style is no one's favorite, yet gofmt is everyone's favorite".

And things like the lack of abstractions and generics are what create a community that's less reliant on dependencies. "A little copying is better than a little dependency" and you can see it in stark contrast to something like the JS community with its require('left-pad') NPM ecosystem.

So, yeah, I like that they didn't fragment the community around something as arbitrary as this. And I get that some people won't like it, just as they don't like the lack of generics, but there is strength in some of these approaches that isn't immediately obvious.

[+] KirinDave|6 years ago|reply
> Do I particularly like managing errors that way? No, but I do think that it improves the transparency and quality of a lot of Go projects.

So long as we can all agree that it feels super bad, I guess this is fine. But it does sort of mean that Golang approaches the Java world back with checked exceptions where principle trumped ergonomics.

That lead to a world where folks felt "forced" to use Java, and that's a sticky label that's difficult to remove. I think the Golang community is going to find itself growing more slowly as folks increasingly realize other options offer similar benefits without the bad ergonomics.

[+] inlined|6 years ago|reply
> errors being values

Though with generics we could have the error values be less invasive. Learning the Scala mindset was eye opening. For e.g. the design patterns of an Optional[T]’s primary code flow are the same as a Try[T,E].

With common transformation idioms, you learn to recognize code patterns the same way one might recognize data structures. It’s no less magical and it simplifies greatly.

[+] leshow|6 years ago|reply
> It's a language intended to have few primitives with an emphasis on code being transparent and errors being values, requiring you to think about what they might be at each point as you're forced to carry them up the chain.

All of this is also true of the generic implementation with Result. Except that (IMO) it's much nicer to work with.

[+] smcl|6 years ago|reply
> And things like the lack of abstractions and generics are what create a community

> that's less reliant on dependencies. "A little copying is better than a little

> dependency" and you can see it in stark contrast to something like the JS community

> with its require('left-pad') NPM ecosystem.

The dependency-hell of node projects is in no way whatsoever related to sensible, accepted programming paradigms like generics. Their absence from Go is a widely accepted shortcoming of the language. It doesn't make Go a bad language, and it doesn't reflect on you or anyone in the Go community who enjoy using the language, but you don't have to try so hard to rationalise their absence, especially since they're one of the more prominent things in the Go 2 drafts.

[+] shanemhansen|6 years ago|reply
Do I like verbose errors? No. Do I like explicit errors? Yes. This is why generics and a Result<T> type will be nice because we will be able to factor out that explicit error handling.
[+] kerng|6 years ago|reply
There were languages like that in last millenium, like C.

Maybe something like vectored error handling (like in Basic) would fit the language better - was curious why Golang didnt implement that - seems a natural pattern their model would work well with.

[+] nkozyra|6 years ago|reply
> and you can see it in stark contrast to something like the JS community with its require('left-pad') NPM ecosystem.

Is it fair to compare external packages to core language features?

There is nothing preventing a go mod/dep left-pad

[+] crimsonalucard|6 years ago|reply
The problem with this is that code that can potentially produce errors cannot compose.

You need a value that is either correct or an error, not something that returns two values.

[+] abtinf|6 years ago|reply
> It's a language intended to have few primitives with an emphasis on code being transparent and errors being values, requiring you to think about what they might be at each point as you're forced to carry them up the chain.

Along these lines, I would have much preferred to see the opposite of this proposal: the total removal of named returns. They add magic and confusion, and they are redundant with normal returns. Except in the absolute simplest and shortest functions, I always reject named returns during code review. They are currently the only example of C++ style policy declaring we-don’t-use-that-feature-in-our-org I’ve run into with Go. Try/check would’ve been the second.

[+] neop1x|6 years ago|reply
I agree. Handling errors is difficult and that is what it is. Many times errors can be handled properly in the function and "if" helps you think about it. Programmers shouldn't be lazy to handle errors, just forwarding them to the caller. That way it may end up like Java, where many functions throw something but lots of programmers don't care so programs simply crash with a long, confusing, unhandled exception stacktrace. How many ppl handle I/O errors in Python for example? Since I started using Go, my software is much more stable.
[+] fredmorcos|6 years ago|reply
> And things like the lack of abstractions and generics are what create a community that's less reliant on dependencies. "A little copying is better than a little dependency" and you can see it in stark contrast to something like the JS community with its require('left-pad') NPM ecosystem.

"A little copying", "less reliant on dependencies"... do you even vendor bro

[+] pbreit|6 years ago|reply
If it matters to anyone, this novice finds “if” easier to understand than “try”.

Very refreshing for novice to agree on expert on a topic.

[+] jph|6 years ago|reply
Kudos to the Go team for their process on this. IMHO it's worth reading Russ Cox's explanation of the problem area, including examples, and comparisons to other languages e.g. Rust and Swift.

https://go.googlesource.com/proposal/+/master/design/go2draf...

[+] 0815test|6 years ago|reply
"But Rust has no equivalent of handle: the convenience of the ? operator comes with the likely omission of proper handling." what's that supposed to mean? The ? operator just bails out if an Error result is returned from the called function, and forwards that Error to the caller. Cleanup is performed implicitly by drop implementations (destructors) using the RAII pattern ala C++.
[+] pcwalton|6 years ago|reply
I suspected this was coming, and it's unfortunate. If Go had implemented try, then in a year everyone would be happy using it and the controversy would have died down. I've seen this happen before.

Unfortunately, the community that has sprung up around Go is more or less opposed to new language features on principle.

[+] helper|6 years ago|reply
> Unfortunately, the community that has sprung up around Go is more or less opposed to new language features on principle.

I think this comes straight from the original go team. Rob Pike had a talk[1] that is partly about why go doesn't keep adding features and why it doesn't have certain features that other languages have. I think people who like go have bought into the idea that the go team has made good trade-offs to make go code easier to read and maintain at the expense of expressibility.

[1]: https://www.youtube.com/watch?v=rFejpH_tAHM

[+] gridlockd|6 years ago|reply
The controversy may have died down, but the impact on code written would have been permanent.

There's a lot of value to there being "one way to do things", even when it's not the best way from any particular point of view.

Go holds this principle higher than most other languages and I think that should be either embraced, or one should look elsewhere - and I'm saying that as someone who "looked elsewhere".

[+] unixsheikh|6 years ago|reply
This is great news.

I really like how errors are handled in Go and I hated this proposal.

The current implementation forces you to constantly think about errors at each single point and it is extremely good at standing out. This is something very valuable, not something that requires or needs to be hidden behind syntactic sugar. It improves the readability of the code and the quality of the software.

If it ain't broke, don't fix it.

[+] pcwalton|6 years ago|reply
Go does not force you to think about errors at every single point. If a function returns only an error (such as, for example, os.Mkdir), the language will happily let you drop the error on the floor.
[+] closeparen|6 years ago|reply
Typing “if err != nil { return nil, err }” a million times is not thought.
[+] curtis|6 years ago|reply
A lot of Go programmers didn't like this proposal at all. I'd like to think this is just because they didn't think it was good enough. However, it seems that many, many Go programmers didn't like it because they think Go error handling is just fine the way it is.
[+] guessmyname|6 years ago|reply
I am one of the Go programmers who didn’t like this proposal.

I also spent a significant amount of time discussing with many people, including the Go team, and I am glad the proposal was declined, not because I like “if err != nil {…}” but because the proposal to add “try()” was not solving a good problem. Many, and I would say, every Go programmer wants better error handling, but “try()” was not it.

I hope the Go team keeps exploring other ideas to hopefully one day have a better error handler.

[+] sagichmal|6 years ago|reply
Go error handing _is_ fundamentally fine the way it is.

That is, the verbosity would certainly benefit from some sugar, but the semantics -- errors managed by separate expressions/blocks immediately adjacent to the error-generating code -- is fundamental to the language, and one of its great strengths.

[+] pixelrevision|6 years ago|reply
I don't really care about try/catch, I'd just rather they come up with a standard for wrapping errors so there is more visibility as they get bubbled up. Currently you can write code to do this but most packages will not be doing the same. There also will always be some member of your team fighting you about "simplicity" when you talk about wanting to have more info than a string to log.
[+] rbtprograms|6 years ago|reply
Good on the Go Team listening to the community, I definitely saw more people against this feature than for it.

I hope they take another stab at improving error handling. I like Go a lot and do think error handling is one place it could use improvements.

[+] farah7|6 years ago|reply
I didn't have particularly strong feelings towards this proposal (maybe just slightly against it) but it's probably important to note that people who are against it are generally much more vocal and make their voices are heard whereas those who like it just give it a thumbs up/tacit approval and keep it moving. Wish I knew how to accurately gauge the opinion of proposals from user communities.
[+] AnimalMuppet|6 years ago|reply
I don't understand why anyone would be (strongly) against this proposal. If I understand it correctly, it's just a shortcut. That is, the old (existing) way would still work. If anyone didn't like "try", well, don't write your code that way.

It would also appear to be amenable to an automated tool that would convert to or from try-style.

Given that, why would people have strong feelings against? Because they think go needs something better, and if this passes, they'll never get it?

[+] poweroftrue|6 years ago|reply
Just try writing three Go programs with error handling, then, try other languages!

I was pissed at first. However, now I cannot code in any language without overusing try and being scared of each line.

Using Go's error handling is actually making your code smarter, I mean, you don't want your code to break with a weird message because of something stupid.

The simplest example is adding a default-path whenever I'm reading a file, Go's error handling reminds me of what to do if this file doesn't exist! Or cannot read etc.

Don't take my word for it, Go ;) try it.

[+] vegancap|6 years ago|reply
Quite rightly, too! It's annoying for beginners, but you quickly see the utility in the if err != nil {} approach, or 'sad path' approach after a few years of using Go in production. You learn to love it! To be honest, there's very little I'd add to the Go language, if anything. It's very unique that most Go developers share that view of a language. With Javascript, for example, I can't wait for 'new stuff', I think that's sometimes symptomatic of a broader dissatisfaction.
[+] voidfunc|6 years ago|reply
It's rather disappointing that Go has managed to bungle error handling so badly in a language only a handful of years old.
[+] alexbanks|6 years ago|reply
This thread is rife with "Go should have Try because I want Try" that also seem to be made by developers that do not write Go. It seems confusing to me that voices generally involved from Go are so demanding of its maintainers.

Curious, are there full-time (or at least Primary) Go developers that are upset by the lack of Try?

[+] apta|6 years ago|reply
> Curious, are there full-time (or at least Primary) Go developers that are upset by the lack of Try?

I use golang at an employer. error handling in golang is verbose, error prone, distracting, and difficult to make sense of when there is actually an error (composing). I've seen on several occasions now errors being mishandled (either dropped by accident, or by overwriting already existing error variables in the same scope). These issues don't happen with exceptions.

[+] qtplatypus|6 years ago|reply
I am a full time developer in go. I feel the lack of good error handling every time I write a function call and then have to use the same if statement to check its result.
[+] dalyons|6 years ago|reply
I write a lot of go in the context of web(micro)services. In stateless services it’s almost always better to bubble up the error and let the caller retry. So I hate the current error handling in this context, it’s a verbosity tax with no value add. Am ambliviant about try though
[+] break_r|6 years ago|reply
> Curious, are there full-time (or at least Primary) Go developers that are upset by the lack of Try?

I am a full-time Go developer. Error handling in Go is miserable. `try` would have made it slightly less miserable.

[+] cwojno|6 years ago|reply
Personally, I feel that the motivation for the issue is one of convenience. The most common use case is changing the flow control in the event of an error to return from the current stack. I'm not a fan of defining an error handler. This seems far too intrusive and cumbersome and a bridge too far.

GoLand gets around this somewhat by adding in the Live Template of "err" being a macro expansion for the if err != nil { return }. However, it still adds those 3 lines below each requisite call.

If they added a new keyword that took the place of this macro, would that be too intrusive? Clearly, this only works if you have named return values.

It would be nice if there was a bash/Ruby-like chaining, such as:

  var1, var2, var3, err := call1(args) &&
  var4, var5, var6, err := call2(args) &&
  ... and more calls and so on ...
  return callN(args)
Where "&&" would perform the if err != nil { return } in-line. Should the first call return a non-nil error as the last argument, flow would be returned to the caller. If not, the flow continues as normal.

This could even be extended in the case of function chaining:

  return call3( call2( call1(args) && ) && )
The downside of using && is that it's overloading the && and may cause some compiler/developer confusion. This was just an example based on a familiar use case (bash); another token can be used.

Rasky suggested something like this based on another proposal in the thread, but using "?" instead.

Another way to approach this might be an overlay language analogous to Kotlin. There could be a Go dialect that compiled into Go that provided this feature. Or, possibly an optional "plugin" for go's compiler that added an intermediate transformation step prior to compilation based on new keywords, but this will frustrate debugging and lead to other surprises. Generators tried to do this, but it doesn't seem to have taken off, from the repos I've read.

Just my 2c

[+] mattxxx|6 years ago|reply
I think this is the right decision. Error-handling the go-way focuses on whether a single operation failed, rather than how a set of operations failed.

In Python or Java, you see a lot of try-catches around blocks of code, which can obfuscate where the source of the error is, despite having particular handling for the type of error.

For systems code, I mostly care about whether something failed... like: - Was the socket opened? - Was the file created? - etc.

[+] quotemstr|6 years ago|reply
With try, Go might have been a language I'd have enjoyed using. It's a shame. Right now, I see Go as being anti-abstraction and anti-cleverness, and I'd rather not work on codebases in which the language of choice is designed to deter creativity and encourage monotony. Heavy use of Go is a big negative when I evaluate potential projects to work on.
[+] drivebyops|6 years ago|reply
Great that they listened to the community
[+] willbw|6 years ago|reply
Try not. Do. Or do not. There is no try.
[+] segmondy|6 years ago|reply
Lack of try and go's error handling is part of my attraction to go. Explicit handling of error is much better than implicit and having to guess how things might get handled.
[+] badrabbit|6 years ago|reply
Has the idea of making the returned error implicit and handling(or discarding) of the return value mandatory been explored? Thinking on the lines of errno in C.
[+] kerng|6 years ago|reply
Well, that seems like the most obvious feature add to Go.