News for hackers. Stuff that matters.
Re:(On | No) Syntactic Support for Error Handling by anentropic on Tuesday June 03, 2025 @02:45PM (#44173251)
It's probably already answered somewhere, but I am curious why it's such a problem in Go specifically, when nearly every language has something better - various different approaches ... is the problem just not being able to decide / please everyone, or there's something specific about Go the language that means everyone else's solutions don't work somehow?
Re:(On | No) Syntactic Support for Error Handling by ok_dad on Tuesday June 03, 2025 @02:49PM (#44173289)
Go has specific goals like not hiding control flow. This would go against those goals, at least the ways people have thought to do it so far.
Re:(On | No) Syntactic Support for Error Handling by tialaramex on Tuesday June 03, 2025 @02:52PM (#44173319)
I don't see how Try (the ? operator) is hidden control flow. It's terse, but it's not hidden.
Re:(On | No) Syntactic Support for Error Handling by 9rx on Tuesday June 03, 2025 @04:04PM (#44174103)
Even the laziest programmer is going to want to wrap the error with another error, and usually you will want to do more than that.

You can put that in-band, with something like:

    v := funcWithError()? err := { 
        return fmt.Errorf("lazy programmer wrapping: %w", err)
    }
But in that case what have you really gained?

Or you can do some kind of magic to allow it to happen out of band:

    // found somewhere else in the codebase
    func wrapErr(err error) error {
        if err == nil {
            return nil
        }
        return fmt.Errorf("lazy programmer wrapping: %w", err)
    }

    v := funcWithError()?(wrapErr)
        
But that's where you start to see things hidden.
Re:(On | No) Syntactic Support for Error Handling by jchw on Tuesday June 03, 2025 @03:25PM (#44173661)
IMO: because it behaves like structured control flow (i.e. there is a branch) but it doesn't look like structured control flow (i.e. it doesn't look like there is a branch; no curly braces). I don't think there's a single other case in the Go programming language: it doesn't even have the conditional ternary operator, for example.
Re:(On | No) Syntactic Support for Error Handling by LoganDark on Tuesday June 03, 2025 @04:11PM (#44174178)
`return` doesn't have braces either.
Re:(On | No) Syntactic Support for Error Handling by jchw on Tuesday June 03, 2025 @05:55PM (#44175198)
Closest thing to a real interblock branch without braces, IMO, is `break` and `continue`, but those are both at least lone statements, not expressions. It "looks like" control flow. Personally, I don't count `return`, I view it as it's own thing from a logical standpoint. Obviously if we were talking about literal CPU doing a jump, well then a lot of things would count, but that's not what I mean in the frame of structured control flow and more in the realm of implementation details.
Re:(On | No) Syntactic Support for Error Handling by tialaramex on Wednesday June 04, 2025 @04:25AM (#44178452)
I could have sworn that like most modern languages Go has `break label` although being statement oriented it doesn't have `break label value`.
Re:(On | No) Syntactic Support for Error Handling by LoganDark on Wednesday June 04, 2025 @05:55AM (#44178999)
I love Rust's ability to return a value from a loop, it's so nice.
Re:(On | No) Syntactic Support for Error Handling by jchw on Wednesday June 04, 2025 @09:58AM (#44180818)
It does. Hell, Go also has a goto statement as well, although obviously that's unstructured control flow.

A more refined version of what I originally said would say "conditional branch" instead of "branch", but I'll admit that my original message should have been worded more carefully. I think people understood it, but taken literally it's not a strong argument.

Re:(On | No) Syntactic Support for Error Handling by _kidlike on Wednesday June 04, 2025 @01:01AM (#44177378)
the obvious solution is try-catch, Java style. Which I'm surprised it's not even mentioned in the article. Not even when listing cons that wouldn't have been there with try-catch.

But of course that would hurt them and the community in so many levels that they don't want to admit...

Re:(On | No) Syntactic Support for Error Handling by jchw on Wednesday June 04, 2025 @01:59AM (#44177629)
I strongly do not like try/catch. Just to list the limitations of exceptions that come to mind,

- try/catch exceptions obscure what things can throw errors. Just looking at a function body, you can't see what parts of the functions could throw errors.

- Relatedly, try/catch exceptions can unwind multiple stack frames at once, sometimes creating tricky, obscure control flow. Stack unwinding can be useful, especially if you really do want to traverse an arbitrary number of stack frames (e.g. to pass an error up in a parser or interpreter, or for error cases you really don't want to think about handling as part of the normal code flow) but it's tricky enough that it's undesirable for ordinary error handling.

- I think most errors, like I/O errors, are fairly normal occurrences, i.e. all code should be written with handling I/O errors in mind; this is not a good use case for this type of error handling mechanism—you might want to pass the error up the stack, but it's useful to be confronted with that decision each time! With exceptions, it might be hard to even know whether a given function call might throw an I/O error. Function calls that are fallible are not distinguishable from function calls that are infallible.

- This is also a downside of Go's current error handling; with try/catch exceptions you can't usually tell what exceptions a function could throw. (Java has checked exceptions, but everyone hates them. The same problem doesn't happen for enum error types in Rust Result, people generally like this.)

(...But that's certainly not all.)

Speaking just in terms of language design, I feel that Rust Result, C++ std::expected, etc. are all going in the right direction. Even Go just having errors be regular values is still better in my opinion.

(Still, traditional exceptions have been proposed too, of course, but it wasn't a mistake to not have exceptions in Go, it was intentional.)

Re:(On | No) Syntactic Support for Error Handling by 9rx on Wednesday June 04, 2025 @11:27AM (#44181788)
> but it wasn't a mistake to not have exceptions in Go, it was intentional.

Go has exceptions! It even uses them (see encoding/json, for example). And they are equally there for you to use.

It wasn't a mistake to promote not overusing them, but that sentiment is not unusual. The Ruby community comes to mind as having also promoted favouring error values over exceptions[1] long before Go existed.

Java leaned into a bad idea, but is not exactly representative of the state of the union.

[1] Ruby on Rails went against the grain, while simultaneously marketing itself towards Java developers doing "XML sit-ups", so that sect within the greater Ruby community tends to be more of the Java school of thought.

Re:(On | No) Syntactic Support for Error Handling by 9rx on Wednesday June 04, 2025 @01:29PM (#44183256)
> but it wasn't a mistake to not have exceptions in Go, it was intentional.

It does have them, though, and always has. Use is even found in the standard library (e.g. encoding/json). They are just not commonly used for this because of the inherit problems with using them in this way as you have already mentioned. But you can. It is a perfectly valid approach where the tradeoffs are acceptable.

But, who knows what the future holds? Ruby in the early days also held the same preference for error values over exceptions... Until Ruby on Rails came along and shifted the prevailing attitude. Perhaps Go will someday have its "Ruby on Rails" moment too.

Re:(On | No) Syntactic Support for Error Handling by jchw on Wednesday June 04, 2025 @03:58PM (#44184847)
Disagree. We could argue what counts as "exceptions", the jargon goes places (e.g. CPU exceptions are nothing to do with "exception handling" for example.) I'd argue that in the modern day programming language exception handling is the type where you have structured control flow dedicated to just the exception handling. Go has stack unwinding with panic and recover, but those are just normal functions, there's no try, no catch, and no throw, and no equivalent to any of those. C also has setjmp/longjmp which can be used in similar ways, but I wouldn't call that exception handling either.

But I think we'll have to agree to disagree on that one, since there's little to be gained from a long debate about what jargon either does or should subjectively mean. Just trying to explain where I'm coming from.

Re:(On | No) Syntactic Support for Error Handling by 9rx on Wednesday June 04, 2025 @04:30PM (#44185144)
> We could argue what counts as "exceptions"

What is there to debate? An exception, by every definition I have ever encountered, is a data structure that contains runtime information (e.g. a stack trace) to stand in for a compiler error where the compiler was not sufficiently capable of determining the fault at compile time. It couldn't possibly mean anything else in reason.

Of course, we're really talking about "exception handlers", not "exceptions".

> there's no try, no catch, and no throw, and no equivalent to any of those.

There can be in name and reasonable equivalency: https://go.dev/play/p/RrO1OrzIPNe I'm not sure what it buys you, though. You haven't functionally changed anything. For this reason, I'm not convinced by the signifaince of syntax.

Think about it. Go could easily provide syntax sugar that replaces `try { throw() } catch (err) {}` with `try(func() { throw() }).catch(func(err) {})`. That would truly satisfy your requirements in every way. But what, specially, in that simple search and replace operation says "exceptions" (meaning exception handlers)?

> C also has setjmp/longjmp which can be used in similar ways, but I wouldn't call that exception handling either.

Agreed. You could conceivably craft your own exceptions to carry through the use of setjmp/longjmp, but that wouldn't be a language feature. However, Go does have an exception structure as a built-in.

Re:(On | No) Syntactic Support for Error Handling by jchw on Wednesday June 04, 2025 @06:56PM (#44186458)
The Wikipedia article about Exception handling[1] does a better job discussing the history and background IMO. Also, obviously when we say "exceptions" in a programming language, we're definitely talking about "exception handling", the word is omitted because it's obvious on context. I'd argue that one's on you if you thought otherwise. (If we're just talking about an "exception", well the Go error object is an "exception", but it's pretty obvious you're not merely talking about that.)

True to my word, I won't argue over the definition itself.

[1]: https://en.wikipedia.org/wiki/Exception_handling_(programmin...

P.S.:

> There can be in name and reasonable equivalency: https://go.dev/play/p/RrO1OrzIPNe I'm not sure what it buys you, though. You haven't functionally changed anything. For this reason, I'm not convinced by the signifaince of syntax.

To me this is no different than implementing "exception handling" with setjmp/longjmp, just less work to do. For example, Go doesn't have pattern matching; implementing an equivalent feature with closures does not make this any less true.

Re:(On | No) Syntactic Support for Error Handling by 9rx on Thursday June 05, 2025 @09:29AM (#44191536)
> The Wikipedia article about Exception handling[1]

What's that old adage? I think it goes something like "The wiki is always accurate—except when it’s about something you know personally." If you don't enough about the topic to discuss it yourself, what are you doing here?

> Also, obviously when we say "exceptions" in a programming language, we're definitely talking about "exception handling"

Not necessarily. Often it is important to discuss the data structure and not the control flow. Strictly, "exception" refers to either the broad concept of exceptional circumstances (i.e. programmer error) or the data structure to represent it. "Exception" being short for "exception handling" where context is clear is fine, but be sure context is clear if you want to go down that road – unless you like confusing others, I suppose.

> well the Go error object is an "exception"

You mean the error interface? That's not an exception. It's just a plain old interface; literally `type error interface { Error() string }`. In fact, the only reason it gained special keyword status is because it being part of the standard library, where it was originally defined in early versions, caused cyclical import headaches. If Go supported circular imports, it would be a standard library definition instead of a keyword today.

The underlying data structure produced when calling panic is an exception, though. It carries the typical payload you'd expect in an exception, like the stack trace.

Of course, errors and exceptions are conceptually very different. Errors are for things that happen in the environment – invalid input, network down, hard drive crash, etc. Exceptions are for programmer mistakes – faults that could have theoretically been detected at compile time if you had a sufficiently advanced compiler. Obviously you can overload exceptions to carry unexceptional information (as you can overload errors to carry exceptional information), and a pragmatist will from time to time, but that's not the intent for such a feature[1].

> To me this is no different than implementing "exception handling" with setjmp/longjmp, just less work to do.

Aside from the fact that there is actually an exception involved. Again, while you might be able to hand roll your own exception data structure in C, it does not provide it for you like Go does. If setjmp/longjmp were paired with an exception data structure of the box, it would reasonably considered exceptions, naturally.

However, the second bit was the real meat of that. A tiny bit of search and replace and you have a system that is effectively indistinguishable from exception handling in languages like Java, Javascript, etc. You haven't explained what about that search and replace, that does not introduce any other new language features or introduce any new concepts, turns what is not exceptions into exceptions.

[1] Java and its offspring's failed experiments in seeing if errors and exceptions could reasonably be considered the same thing excepted.

Re:(On | No) Syntactic Support for Error Handling by jchw on Thursday June 05, 2025 @08:15PM (#44196766)
This is a lot of words, but it's just a miscommunication: when we say exception handling, we mean try/catch. If you want to disagree on the definition or semantics then feel free.
Re:(On | No) Syntactic Support for Error Handling by 9rx on Friday June 06, 2025 @10:32AM (#44201330)
What miscommunication are you speaking of? "Exceptions" was understood to mean "exception handlers" from the beginning. I even expressed that understanding earlier. While you've taken us down some interesting tangents, for whatever strange reason you found it relevant, the core discussion about exception handling has also remained intact.

But you seem to want to avoid talking about it? Let's try one more time: What is it about dead-simple search and replace, without adding any other new features or technical concepts, that turns what is "not exceptions" into something that is "exceptions"? Because I don't understand the difference that makes.

Re:(On | No) Syntactic Support for Error Handling by jchw on Sunday June 08, 2025 @11:43AM (#44217649)
All of the languages are turing complete; the fact that you can make them do the same things with relatively simple transforms isn't actually surprising, it is in fact a natural consequence. Of course, you can do the same thing with nearly any stack unwinding primitive as long as it's general enough like panic/recover.

Language decisions scoped try/catch are not incidental details.

Re:(On | No) Syntactic Support for Error Handling by 9rx on Wednesday June 04, 2025 @11:56AM (#44182154)
> the obvious solution is try-catch, Java style.

Go already has that: https://go.dev/play/p/RrO1OrzIPNe

> Not even when listing cons that wouldn't have been there with try-catch.

The cons are already well known. That's why you're already not using the feature that has existed since the very first release (in most cases that is; there is certainly a time and place for everything — even the standard library uses it sometimes!).

Re:(On | No) Syntactic Support for Error Handling by ok_dad on Tuesday June 03, 2025 @03:18PM (#44173590)
I personally agree, but I’m not the go team. The hidden control flow was specifically called out but about the try keyword. I like the ? and similar ways of checking nulls, but personally I don’t mind the verbosity in go, even if there are footguns.
Re:(On | No) Syntactic Support for Error Handling by kiitos on Tuesday June 03, 2025 @04:39PM (#44174464)
Currently if you want to return from a function/method you need to type `return` in the source code. And return is a single expr, it can't be chained or embedded, and in almost all cases it exists on its own line in the file. This is an important invariant for Go, even if you don't understand or buy its motivation. `?` would fundamentally change that core property of control flow. In short, chaining is not considered to be a virtue, and is not something that's desired.
Re:(On | No) Syntactic Support for Error Handling by skywhopper on Tuesday June 03, 2025 @06:56PM (#44175654)
That only covers one tiny case among several possible error flows. Why add special syntax for that?
Re:(On | No) Syntactic Support for Error Handling by LinXitoW on Tuesday June 03, 2025 @07:34PM (#44175889)
Isn't defer hidden control flow? The defer handling can happen at any point in the function, depending on when errors happen. Exactly like a finally block.
Re:(On | No) Syntactic Support for Error Handling by hackingonempty on Tuesday June 03, 2025 @02:55PM (#44173348)
The language is designed for Google, which hires thousands of newly graduated devs every year. They also have millions of lines of code. In this environment they value easy of onboarding devs and maintaining the codebase over almost everything else. So they are saddled with bad decisions made a long time ago because they are extremely reluctant to introduce any new features and especially breaking changes.
Re:(On | No) Syntactic Support for Error Handling by skywhopper on Tuesday June 03, 2025 @06:54PM (#44175644)
The thing is, it’s not actually a major problem. It’s the thing that gets the most complaints for sure, and rubs folks from other languages the wrong way often. But it’s an intentional design that is aware of its tradeoffs. As a 10 year Go veteran, I strongly prefer Go’s approach to most other languages. Implicit control flow is a nightmare that is best avoided, imo.

It’s okay for Go to be different than other languages. For folks who can’t stand it, there are lots of other options. As it is, Go is massively successful and most active Go programmers don’t mind the error handling situation. The complaints are mostly from folks who didn’t choose it themselves or don’t even actually use it.

The fact that this is the biggest complaint about Go proves to me the language is pretty darn incredible.

Re:(On | No) Syntactic Support for Error Handling by ivanbakel on Wednesday June 04, 2025 @05:49AM (#44178951)
> As it is, Go is massively successful and most active Go programmers don’t mind the error handling situation. The complaints are mostly from folks who didn’t choose it themselves or don’t even actually use it.

This is a case of massive selection bias. How do you know that Go’s error problem isn’t so great that it drives away all of these programmers? It certainly made me not ever want to reach for Go again after using it for one project.

Re:(On | No) Syntactic Support for Error Handling by munificent on Tuesday June 03, 2025 @06:55PM (#44175650)
I think the two big things for Go are:

1. Minimalism.

Go has always had an ethos of extreme minimalism and have deliberately cultivated an ecosystem and userbase that also places a premium on that. Whereas, say, the Perl ecosystem would be delighted to have the language add one or seven knew ways of solving the same problem, the Go userbase doesn't want that. They want one way to do things and highly value consistency, idiomatic code, and not having to make unnecessary implementation choices when programming.

In every programming language, there is a cost to adding features, but that cost is relatively higher in Go.

2. Concurrency.

Concurrency, channels, and goroutines are central to the design of the language. While I'm sure you can combine exception handling with CSP-based concurrency, I wouldn't guarantee that the resulting language is easy to use correctly. What happens when an uncaught exception unwinds the entire stack of a goroutine? How does that affect other goroutines that it spawned or that spawned it? What does it do to goroutines that are waiting on channels that expect to hear from it?

There may be a good design there, but it may also be that it's just really really hard to reason about programs that heavily use CSP-style concurrency and exceptions for error handling.

The Go designers cared more about concurrency than error handling, so they chose a simpler error handling model that doesn't interfere with goroutines as much. (I understand that panics complicate this story. I'm not a Go expert. This is just what I've inferred from the outside.)

Re:(On | No) Syntactic Support for Error Handling by dcow on Tuesday June 03, 2025 @07:28PM (#44175855)
(2) hasn’t been a problem for Swift or Rust, both of which have the ability to spawn tasks willy nilly. I don’t think we’re talking about adding exceptions to Go, we’re talking about nicer error handling syntax.

(1) yes Go’s minimal language surface area means the thing you spend the most time doing in any program (handling error scenarios and testing correctness) is the most verbose unenjoyable braindead aspect. I’m glad there is a cultivated home for people that tolerate this. And I’m glad it’s not where I live…

Re:(On | No) Syntactic Support for Error Handling by mamcx on Tuesday June 03, 2025 @09:38PM (#44176469)
> is the problem just not being able to decide / please everyone,

Reading this article? in fact yes(?):

> After so many years of trying, with three full-fledged proposals by the Go team and literally hundreds (!) of community proposals, most of them variations on a theme, all of which failed to attract sufficient (let alone overwhelming) support, the question we now face is: how to proceed? Should we proceed at all?

> We think not.

This is a problem of the go designers, in the sense that are not capable to accept the solutions that are viable because none are total to their ideals.

And never will find one.

____

I have use more than 20 langs and even try to build one and is correct that this is a real unsolved problem, where your best option is to pick one way and accept that it will optimize for some cases at huge cost when you divert.

But is know that the current way of Go (that is a insignificant improvement over the C way) sucks and ANY of the other ways are truly better (to the point that I think go is the only lunatic in town that take this path!), but none will be perfect for all the scenarios.

Re:(On | No) Syntactic Support for Error Handling by Merovius on Wednesday June 04, 2025 @07:05AM (#44179398)
> But is know that the current way of Go (that is a insignificant improvement over the C way) sucks and ANY of the other ways are truly better […]

This is a bold statement for something so subjective. I'll note that the proposal to leave the status quo as-is is probably one of the most favorably voted Go proposals of all time: https://github.com/golang/go/issues/32825

Go language design is not a popularity contest or democracy (if nothing else because it is not clear who would get a vote). But you won't find any other proposal with thousands of emoji votes, 90% of which are in favor.

I get the criticism and I agree with it to a degree. But boldly stating that criticism as objective and universal is uninformed.

Re:(On | No) Syntactic Support for Error Handling by mamcx on Wednesday June 04, 2025 @09:17AM (#44180428)
I understand that the decision could be correct for the situation (ie: if the stated goal is have a proposal with enough support and it was not reached not proceed is correct), that is different that the handling of error as-is is bad (that is the reason the people spend years to solve it)
Re:(On | No) Syntactic Support for Error Handling by Merovius on Thursday June 05, 2025 @05:50PM (#44196125)
> (that is the reason the people spend years to solve it)

I don't think anyone actually spend years trying to solve it. It's just that over the years, many people have tried to solve it - each for a grand total of maybe a week or so. If you look at the list, you'll see a lot of different proposal authors: https://seankhliao.com/blog/12020-11-23-go-error-handling-pr... Most of these do not post any other issues and many of those don't even respond in the discussion to their own proposals.

It's a thing that a lot of people coming to the language get frustrated by, think "here is an obvious way to make this better" and file a (usually half-baked) proposal about. It's not a thing that people spend years of focused effort on to polish into something that works.

Compare that to generics: Not only did Ian file a proposal about that roughly every year. The final design also had over a year of intense discussion, with at least a dozen or two consistent participants (and a hundred or so occasional ones). With at least three or four direct iterations.

Error handling is something that a lot of people care a little about.

Re:(On | No) Syntactic Support for Error Handling by eviks on Thursday June 05, 2025 @09:02AM (#44191303)
This issue contradicts the cited surveys where error handling is identified as the most important issue. Isn't the survey more reliable way to read the community room than a github issue?
Re:(On | No) Syntactic Support for Error Handling by Merovius on Thursday June 05, 2025 @05:39PM (#44196050)
It doesn't really contradict the survey all that much. 13% of respondents said that error handling is the biggest issue. That leaves 87%, which can rank anywhere from "it's an issue, but not the biggest" through "it's a minor nuisance" through "I don't care" up to "I actively like the status quo". We can only guess about the distribution.

And yes, I agree that the survey is a better source of data, generally. But I will also say that it intentionally asks as broad a definition of "Go user" as possible. Meaning it also (intentionally) asks people who might use Go every once in a while at work. And a good chunk of respondents are newcomers. These groups are more likely to identify this as a problem. While people who are active on GitHub tend to bias towards people who use it as a daily driver and are much more used to its idioms.

The data is mixed. I fully acknowledge that. But anecdotally, there seems to be a pretty clear pattern that people who come new to the language complain about this, but then get used to it and at the point where they become active in the community, they prefer the status quo. I don't think the experience of newcomers should be dismissed, but I also think it should be acknowledged that it's something most people get used to.

Re:(On | No) Syntactic Support for Error Handling by Merovius on Thursday June 05, 2025 @06:01PM (#44196189)
Oh and to be clear: I didn't say "look at this issue, most people clearly prefer the status quo". I just said that given this issue, making the claim that the status quo is objectively bad is hard to justify. I said that its badness is clearly subjective.

That is, I criticized the strength of the original claim. I didn't try to make an equally strong opposite claim.