Live data from Hacker News

Gopher Wrangling: Effective error handling in Go

stephenn.com

151–160 of 310 posts

Re: Gopher Wrangling: Effective error handling in Go

#151
post #144
post #116

Go's error handling is a horrible mess: 1. It's easy to ignore returned errors without any compiler warnings. You have to rely on third party tools such as golangci-lint to report missing error handling. 2. Errors don't carry stack traces with them, you have to rely on third party libraries or custom errors to get that functionality and you will only get it for your own code, not in other libraries you are using. 3.…

>3. It's unclear who should add context to error messages is it the caller or callee? Usually it gets skipped, leading to useless error messages Why is that unclear? Let's say you are writting a db client package and a service around it. The package's db.Exec(query) method should return and error that will have an error text received from db if any AND\OR context from the package itself. Then in your service you add…

>>3

> Why is that unclear?

The usual advice is to follow what the stdlib does. Let's look at an example. Let's say we close a file and then try to set a deadline on it:

    f, _ := os.Create("/tmp/filename")
    f.Close()
    fmt.Printf("%v", f.SetDeadline(time.Now()))

    // output: use of closed file
Okay, so in this case, it's the caller's responsibility to keep track of the filename and add the context of what file was already closed, resulting in that error.

However, what about the error for trying to write to a closed file?

    _, err := f.Write(nil)
    fmt.Printf("%v", err)    
    
    // output: write /tmp/filename: file already closed
Oh, I see, it's Write's responsibility to add the context of the filename. Huh.

This is a clear example of the problem the parent is talking about. The 'os.File' construct knows the filename. Sometimes it adds that as context to errors, sometimes it doesn't. Sometimes the caller needs to add it in, sometimes the callee has already added it.

Re: Gopher Wrangling: Effective error handling in Go

#152
post #18

Earlier quoted context omitted.

It looks like sync/errgroup is a proposal, but not in the standard library (not yet, at any rate): https://github.com/golang/go/issues/57534

Oh that's right. I imported it via golang.org/x/sync/errgroup

Even the author of errgroup does not want errgroup to enter the stdlib for the reasons he mentions:

There are two significant problems with the API:

An errgroup.WithContext today cancels the Context when its Wait method returns, which makes it easier to avoid leaking resources but somewhat prone to bugs involving accidental reuse of the Context after the call to Wait.

The need to call Wait in order to free resources makes errgroup.WithContext unfortunately still somewhat prone to leaks. If you start a bunch of goroutines and then encounter an error while setting up another one, it's easy to accidentally leak all of the goroutines started so far — along with their associated Context — by writing

Re: Gopher Wrangling: Effective error handling in Go

#153
post #140

Earlier quoted context omitted.

> Convention is just an educated guess. at some absolute level yes, but at any pragmatic level no, definitely not > No. The answer is no. I'm not only free to say "no," but if I'm honest and truthful I am compelled to say "no." nope! wrong. do not pass go, etc. -- it's a spectrum

>nope! wrong. do not pass go, etc. -- it's a spectrum You are simply incorrect, there's no nuance or room for interpretation. A compiler can guarantee "A or B, but not both or neither", "A or B or both, but never neither", or even "A or B or both or neither" but convention for (A, B) in Go cannot, therefore it is not as good. Go's conventions are not as good as a decent type system, there's no spectrum about it; Go i…

you're saying that guarantees which are not enforced by the compiler are "not as good" as those which are

this is not correct

but i'm not sure how to convince you of this truth, so (shrug)

Re: Gopher Wrangling: Effective error handling in Go

#154
post #91

Could someone explain why is Go so hyped? In my personal opinion it is just not a good language, and I think many judge it based on some false basis that it is somehow “close to the hardware” because it produces a binary. Like, the amount of time it is put next to Rust when the two have almost nothing in common.. It is very verbose, yet Java is the one that is called that, often by Gophers, which is much more concise…

I agree that go and rust have different areas, but that was less clear when they were getting started. Back then go was trying to figure out what it meant by 'systems programming language' and rust had a similar threading model.

Another point is that they do share similarities, which might we might now just describe as being 'modern': They're generally procedual -- you organize your code into modules (not classes) with structs and functions, they generally like static linking, type inference for greater ergonomics, the compiler includes the build system and a packager manager, there's a good formatter.

The above are points for both rust and go compared to C/C++, Python, Java, etc.

So why do I like go? I think mostly it's that it makes some strong engineering trade-offs, trying to get 80% for 20% of the price. That manifests itself in a number of ways.

It's not the fastest language, but neither is it slow.

I really dislike exceptions because there's no documentation for how a function can fail. For this reason I prefer go style errors, which are an improvement on the C error story. Yes it has warts, but it's 80% good enough.

It's a simple language with batteries included. You can generally follow the direction set and be happy. It leads itself to simple, getting-things-done kind of code, rather than being over-abstracted. Being simple also makes for great compile times.

Re: Gopher Wrangling: Effective error handling in Go

#155

Earlier quoted context omitted.

given a function fn that can fail, it will return a result and an error e.g. result, error = fn(...) calling this function should yield to the caller two possibilities, somehow: a success value _or_ a failure error the important thing is that in both cases, the control flow is visible in the source code as written result, error = fn(...) if there was an error, ... if it was successful, ... when an expression fails, y…

Yeah, but you're still relying on the programmer to do it correctly which is nothing but false hope.

no, it isn't

Re: Gopher Wrangling: Effective error handling in Go

#156

Earlier quoted context omitted.

given a function fn that can fail, it will return a result and an error e.g. result, error = fn(...) calling this function should yield to the caller two possibilities, somehow: a success value _or_ a failure error the important thing is that in both cases, the control flow is visible in the source code as written result, error = fn(...) if there was an error, ... if it was successful, ... when an expression fails, y…

Nothing is preventing the code from returning both at the same time. I've seen code (including in the standard library) that returns both an error and a return value. In a language with disjoint unions, such cases would be encoded properly.

convention prevents it

and in the case where returning both is OK, then documentation makes that clear

this is not difficult

Re: Gopher Wrangling: Effective error handling in Go

#157
post #136

Earlier quoted context omitted.

In my personal opinion it's a great language to solve problems _I_ have to deal with in course of my work. Can I solve them with Java? Sure. Difference is go does not have the complexity you can find in Java and quite opinionated. So you don't have to spend as much time working with the language inself and can focus on getting the job done. Go is not as expressive and some other languages and does not have the same a…

Could you elaborate on exactly what complexity in Java you're referring to? By having an overly simplistic language, you end up pushing more complexity onto the programmer and into the code base. There is no free lunch. I find it much more sane to solve and express code in Java. You get terser, more to the point code that reflects the underlying logic more clearly, compared to having to read many lines or pages to un…

>By having an overly simplistic language, you end up pushing more complexity onto the programmer and into the code base. There is no free lunch.

Sure, I just don't see this as a problem.

As a result you have

a) a number of third party packages to chose from depending on your needs\opinions

b) you have a more verbose codebase, some people find it harder to deal witih while I find it easier to deal with.

>compared to having to read many lines or pages to understand what's going on.

Different people different ways of thinking I guess.

In my eyes Java code looks to much like a specification in for of a code. Easier to do a code review but harder to actually understand how it works. And I personally need this dive into internals to actually feel confident about the code.

>Could you elaborate on exactly what complexity in Java you're referring to?

I don't have too much experience in Java, but from what I've seen - Java has too many abstractions and OOP for the sake of paradigm and nothing else.

UPD: adezxc's comment is a good addition to mine

Re: Gopher Wrangling: Effective error handling in Go

#158
post #91

Could someone explain why is Go so hyped? In my personal opinion it is just not a good language, and I think many judge it based on some false basis that it is somehow “close to the hardware” because it produces a binary. Like, the amount of time it is put next to Rust when the two have almost nothing in common.. It is very verbose, yet Java is the one that is called that, often by Gophers, which is much more concise…

> Could someone explain why is Go so hyped?

You can write huge code bases with it, the tooling is good.

You can use a moderately skilled work force to achieve good results. When some team members leave, you are not left with some wizardry code base behind.

Re: Gopher Wrangling: Effective error handling in Go

#159
post #140

Earlier quoted context omitted.

>nope! wrong. do not pass go, etc. -- it's a spectrum You are simply incorrect, there's no nuance or room for interpretation. A compiler can guarantee "A or B, but not both or neither", "A or B or both, but never neither", or even "A or B or both or neither" but convention for (A, B) in Go cannot, therefore it is not as good. Go's conventions are not as good as a decent type system, there's no spectrum about it; Go i…

you're saying that guarantees which are not enforced by the compiler are "not as good" as those which are this is not correct but i'm not sure how to convince you of this truth, so (shrug)

Well, yes. I do think something that is guaranteed is better than something that is not guaranteed. You've at least somewhat accurately captured my position, though with the weird implicit assumption that "guaranteed by convention" means anything at all.

>but i'm not sure how to convince you of this truth, so (shrug)

You'd need some pretty compelling evidence to convince me that something that is not guaranteed is as good as something that is guaranteed, so I can see why you're struggling. With your admissions, all I can really say is good luck convincing me or anyone.

Re: Gopher Wrangling: Effective error handling in Go

#160
post #91

Could someone explain why is Go so hyped? In my personal opinion it is just not a good language, and I think many judge it based on some false basis that it is somehow “close to the hardware” because it produces a binary. Like, the amount of time it is put next to Rust when the two have almost nothing in common.. It is very verbose, yet Java is the one that is called that, often by Gophers, which is much more concise…

> Could someone explain why is Go so hyped?

For me, it's:

1) channels (and goroutines, of course)

2) explicit error handling (panics are actually fatal, in contrast to exceptions which are often even used for flow control)

3) easy (cross-)compilation - just go build

And probably a few more reasons I can't remember at the moment. It's just fun to write Go!

Post reply on HN