I'll show you how to sleep comfortably on a stone bed. If you're coming from other styles of appartments or hotels, you will maybe be surprised by the first impression of a stone bed. But I'll show you how to adapt and learn to enjoy sleeping in this new way that some people first feel uncomfortable with due to unfamiliarity with how the extremely cold and hard surface feels.
I'll show you how choosing that hotel with the bed that appears to be comfy will in-fact result in a bad case of bed lice so that instead of a night's discomfort you have have weeks or even months worth of agony. 🤷♂️
what bothering me is not the verbosity of "if err != nil", rather the fact that: (1) "Hidding error and continue running is the nature of Go codes" at least it is the default behavior when you "forgot" to handle error... On the other side, the "Exception paradigm" of Java, C# makes your codes crash if you "forgot" to handle the "exception" other function is throwing. (2) The "if err != nil" of Go is "contaminating" the same way as the "async await". It means that if you "forgot" only one line of "if err != nil" in the chain, then the worst case is that others "if err != nil" (in the chain) might be wasted. The longer the codes continue to run with the hidden error until the day it finally crashed, the harder to track down the root cause. Fortunately this worst case is not that common IME. Moreover, the golangci-lint gives you a big "errchecked" warning. Personally, I don't let any of these warnings appeared in my codes. Evens in case I wanted to skip / ignore an error, I'd still "if err != nil" to log the error (in debug level) along with a justification message explaining why I ignored the error (and so continued the happy path) I wish that Go team would inspire the same approach as Rust for error handling. Rust errors are Value the same way as Go, but the Result of Rust beautifuly "forced" developers to handle error: In order to Get the result T you have to handle the "E" one way or other: in a "match" statement or by a simple unwrap() function to get the T which will panic the E... Unfortunately, It might be too late now for Go to take the same approach as Rust because Go has to keep backward compatibility with the current "if err != nil" way of errors handling.
it doesn't - you can choose to let your functions simply not check if it will return an error by not check for nil or specific errors vars. it's not like other languages doesn't have shit ton of error handling if it's properly robust. It's just that Go kinda requires you to ignore errors instead with either underscore or simply not storing the function return values at all in case where a function only returns an error.
Nice video. One point about wrapped errors; I have always found them to be problematic. The problem with wrapped errors is that when you wrap an error you can't use a sentinel error. I have been looking for a good solution for years, and the best I have come upon with - after trying many other approaches - is to instead use `errors.Join()`, e.g. `err = errors.Join(ErrMySentinelError, err)`. Alternately if I want to include some values - inspired by slog - I might do this instead: `err = errors.Join(ErrMySentinelError,fmt.Errorf("widget=%v",widget), err)`. I don't love the middle argument but that is what I am currently working with. Writing this comment I realize I could create a custom error for the middle on and directly use it like args passed to slog. I think I will update my projects to try that.
People often criticize this way of handling errors, but it is probably due to a majority of people coming from a language where errors are ghosts, and you don't even know they can happen. That's why it might feel easier to deal with errors, because you are not forced to handle them. Sure, maybe some errors almost never happen and it might not even be worth handling them, but in my opinion If a language forces you to do very robust programs, where you handle all scenarios, that's a good thing, not a bad one. If you wanna write lazy code that breaks, but write it in 1 minute, then go with Python, because in Go it will be way harder to do bad code.
I have the urge to run a sed before compiling to add line numbers to go source code. There has to be a better way to find the source of a fault than using programmer supplied strings
Without exploring the different approaches, I would say implement the interface when you want to add additional state/functionality to what the error struct would provide
In my experience it is best not to create a custom error unless there is no other way. Otherwise you end up with a lot more complexity when using the errors.
if you never touched Golang of course it will seem horrible, for me I just create standard approach/plan to handle it and now just follow that approach. it will be really messy if you just try to figure out how to handle it for every time you face error in code.
I'll show you how to sleep comfortably on a stone bed. If you're coming from other styles of appartments or hotels, you will maybe be surprised by the first impression of a stone bed. But I'll show you how to adapt and learn to enjoy sleeping in this new way that some people first feel uncomfortable with due to unfamiliarity with how the extremely cold and hard surface feels.
😂
I'll show you how choosing that hotel with the bed that appears to be comfy will in-fact result in a bad case of bed lice so that instead of a night's discomfort you have have weeks or even months worth of agony. 🤷♂️
what bothering me is not the verbosity of "if err != nil", rather the fact that:
(1) "Hidding error and continue running is the nature of Go codes" at least it is the default behavior when you "forgot" to handle error... On the other side, the "Exception paradigm" of Java, C# makes your codes crash if you "forgot" to handle the "exception" other function is throwing.
(2) The "if err != nil" of Go is "contaminating" the same way as the "async await". It means that if you "forgot" only one line of "if err != nil" in the chain, then the worst case is that others "if err != nil" (in the chain) might be wasted. The longer the codes continue to run with the hidden error until the day it finally crashed, the harder to track down the root cause.
Fortunately this worst case is not that common IME. Moreover, the golangci-lint gives you a big "errchecked" warning. Personally, I don't let any of these warnings appeared in my codes. Evens in case I wanted to skip / ignore an error, I'd still "if err != nil" to log the error (in debug level) along with a justification message explaining why I ignored the error (and so continued the happy path)
I wish that Go team would inspire the same approach as Rust for error handling. Rust errors are Value the same way as Go, but the Result of Rust beautifuly "forced" developers to handle error: In order to Get the result T you have to handle the "E" one way or other: in a "match" statement or by a simple unwrap() function to get the T which will panic the E...
Unfortunately, It might be too late now for Go to take the same approach as Rust because Go has to keep backward compatibility with the current "if err != nil" way of errors handling.
well that's a bummer. I was hoping I was missing something and my code didn't actually need to be 2/3 error handling
it doesn't - you can choose to let your functions simply not check if it will return an error by not check for nil or specific errors vars. it's not like other languages doesn't have shit ton of error handling if it's properly robust. It's just that Go kinda requires you to ignore errors instead with either underscore or simply not storing the function return values at all in case where a function only returns an error.
This exactly what i needed. I came from java and javascript and not having stack tract is bugging me out in golang
Thanks for awesome video. It was super helpful :D
Glad it was helpful!
Nice video.
One point about wrapped errors; I have always found them to be problematic.
The problem with wrapped errors is that when you wrap an error you can't use a sentinel error. I have been looking for a good solution for years, and the best I have come upon with - after trying many other approaches - is to instead use `errors.Join()`, e.g. `err = errors.Join(ErrMySentinelError, err)`.
Alternately if I want to include some values - inspired by slog - I might do this instead: `err = errors.Join(ErrMySentinelError,fmt.Errorf("widget=%v",widget), err)`. I don't love the middle argument but that is what I am currently working with.
Writing this comment I realize I could create a custom error for the middle on and directly use it like args passed to slog. I think I will update my projects to try that.
People often criticize this way of handling errors, but it is probably due to a majority of people coming from a language where errors are ghosts, and you don't even know they can happen. That's why it might feel easier to deal with errors, because you are not forced to handle them.
Sure, maybe some errors almost never happen and it might not even be worth handling them, but in my opinion If a language forces you to do very robust programs, where you handle all scenarios, that's a good thing, not a bad one.
If you wanna write lazy code that breaks, but write it in 1 minute, then go with Python, because in Go it will be way harder to do bad code.
I have the urge to run a sed before compiling to add line numbers to go source code. There has to be a better way to find the source of a fault than using programmer supplied strings
golang preprocessor 😬
thank you for the video! that was very helpful
You're welcome!
When to create a custom error by implementing the error interface, or when to use the errors.New() ?
Without exploring the different approaches, I would say implement the interface when you want to add additional state/functionality to what the error struct would provide
In my experience it is best not to create a custom error unless there is no other way. Otherwise you end up with a lot more complexity when using the errors.
I might be missing some obvious point but it seems Go error handling is horrible..... sooo many lines of code just to handle one error.
if you never touched Golang of course it will seem horrible,
for me I just create standard approach/plan to handle it and now just follow that approach.
it will be really messy if you just try to figure out how to handle it for every time you face error in code.
Sometimes I hate go error handling so much
I like how Rust uses the Result type. I'd like that in go.
I always hate using exceptions for error handling so much. 🤷♂️
errors.As? seriously? not errors.Is or errors.Equals... why would they name it like that. "As" usually implies casting.