Not specific to Go but being able to know that a function can possibly error helps quite a bit. Lots of times I've written python code where I forget that reading a file or connecting to a database can fail. You can say skill issue ofc but having a red squiggly line pop up on your editor while your typing just does something to your brain. With something like python you have to remember that something can throw an error/exception
This 100%. I find that in Golang I'm prompted to handle errors, but in other languages I often trip into them at runtime during a test, and *only then* realize I need to handle them.
I think the larger problem is that most people don't want to think granularly about "what should I do if this thing errors?" And instead have a giant try catch block at the top level and never think about it. So skill issue?
They only want to think about the happy path and assume that everything works just the way it should be and (big) if something happens they just want catch block will take care of that. Yeah skill issue 😂😂
@@user-gs3lm7gt5e that's how you implement stuff, 1st iteration you make it work (happy path), and other iterations are refactoring + error handling. That is why in rust you do .unwrap() and later on on 3rd iteration or so you have to replace all unwraps with error handling
Oh yeah. I appreciate Go's error as values versus Try / Catch style approaches. I use to think that was the absolute best way to handle errors. Then Rust came along and I was blown away. I didn't get it at first, but after a while of actually using it in practice, it's my personal favorite way of error handling by far. Not to say that Go doesn't have a host of benefits over Rust. At this point of using both, it's almost apples to oranges comparison wise. I use them for different use cases, despite having overlapping purposes. It's really strange.
I quite like the syntax, because go actively reminds you that an error may happen and let's you choose whether or not you want to handle it. In Exception based languages, if you want to do robust error handling, you end up with the same amount, if not more boiler plate, it's just that these languages let you ignore it by default, whereas Go makes you think about whether to ignore it or not
Exceptions allow for centralized error handling, which most of the time is what you want. Even in most go programs, you don't handle each error individually, you just "return err". Exceptions also allow you to handle different TYPES of errors differently. This is technically also possible in errors as values, but it's only possible in go when a package provides functions for it, such as "os.IsNotExist", which is totally insane to me. Not to mention that go errors don't provide stack traces. The amount of time I wasted when I had problems with go programs and had to search for where the error I found in the logs actually occurs is unbelievable.
I actually chose Go for my current project because of the error handling. I’m a senior Java developer in my day job but returning errors from a function is so much better than having exceptions thrown at you from 4 levels down in the call stack! I absolutely love the Rust error handling but the rest of the language is just too complex. I did quite a lot of programming in Rust and the thing is Go is the language that gets out of my way. I never have to fight it! I can just get shit done! I would still have loved an Option type in Go or the question mark operator from Rust that would basically let you return the error if thrown if the error types are the same without the if err ≠ nil thing. But hey, there’s no perfect language. Oh and enums! For the love of God why doesn’t Go have at least basic enums!? And no…iota sucks. Still using Go though… 😂
Every javascript or python programmer goes why do I have to write this every time because they used to not handling errors. I like this because Golang you know what could error by using the API or libraries you are using. You are force to think about what do you want to do if that thing error
If you're not adding additional context to your error by wrapping you're not handling errors correctly in Go. This context can also make the code more self-documenting. That being said, it would be nice to have Zig style error handling in Go.
Back in my C# days, I'd get really lazy and do a general try-catch loop and log the exception message. It never really got me to think about types of errors, and really how to handle them based on what the actual error is. At first I was annoyed by the Go approach, but over time it's made me think more about the operations my functions do and how they could fail. Ultimately it has made me a much more thoughtful developer.
I think it's mostly we'd like syntax sugar. err := foo() // base where you need to manually handle it. ! := foo() //panic error ? := foo() //zero all other values in return except for error
I think this pattern is great. Yes, I have to write a few more characters but it's not a big deal. I like that I get more granular control, not a huge "try"messy blob.
The issue is that over time, in really big projects, that few characters end up being 70% of the code base. When all you need is a simple "stop the world, and report". Especially with web projects where loads of content is simply reading content. All that can be solved with a one liner or a "try" function, or a rust ? but yea ... For some reason the Go dev think that people will not be able to handle that much "work".
Thank you for this! While I agree with everything, what I'm missing in Go is a native way to wrap errors with types / by opinionated about using them. I know you can implement the behavior yourself, what I wanted to ask is - do you have a method you normally use? Or do you just use them as strings?
I just created a few snippets for the common error handling patterns, it is not as bad as Twitter makes it seem. You know what is more annoying is surrounding multiple try/catch statements in async/await JS
Thanks for your video!!! Just started playing with Go this week and I like it. I like the fact that errors are values, it has always been a mess for me to deal with errors in typescript.
The fact is that foo, err := bar() if err != nil { return err } could just be replaced with this small syntactic sugar: foo := bar()? I really don't know why they didn't already do this.
Usually, when you have a function func foo() (int, error), you want to express the fact EITHER foo returns an int OR it returns an error. But with the way Go works, nothing prevents foo to return two nil values or two non nil values. I feel like it is a very small downside to Golang's error handling (fixed by convention: checking if err is nil) and that's why I like Rust's error handling more.
This is my only complaint with it. On the other hand, maybe having an error and some kind of value is fine. Both being nil seems like a user error, though. Documentation should describe the behavior better than convention, imo. I think the Result variant model is safer from an error handling perspective, but it is more opinionated. Even in rust, error handling is sort of optional given you don’t have to use it and you can always unwrap if it’s from third party code.
There are cases where it is a valid thing, returning foo *AND* an error. I managed to read 2,753 bytes then an error happened. Error might be network location became unavailable, tried to read past the end of a file, file got deleted while reading, and so much more. Returning both makes sense in those scenarios. You get the data that was read and whatever else happened. Being values, the error can be used in program flow. I know to stop reading if I get the *EOF* error. And the fact that I got an *EOF* won't invalidate whatever data I have in my buffer.
Hi, Melkey. How long have you been working with Golang? And how long did it take you to consider yourself proficient in the technology? I've been working with Golang for 6 months now (junior developer), and even though I study every day, I still don't feel very prepared.
This guy gets it. Love Go, and have been using a lot of Zig lately, and error handling in it solves the minor annoyances of Go's verbosity in error handling, while keeping its strengths in making the user *explicitly* either handle/ignore it. I am not very familiar with Rust, but my understanding is that both it and Zig are similar in how they handle errors.
As someone who comes from JS/TS world into Go - I really like the Go way of handling errors. It forces me to think about extra edge cases which I haven't even been thinking about in the JS world and this "enforces" me to write a higher quality software.
error handling in go is annoying, copilot kinda helps in this regard, but would you rather have a program that crashes every time an error happens inside a function? the alternative is sometimes catching errors, sometimes not, depending on how much you trust your function.
The greatest trick Rob Pike ever pulled was convincing Go programmers that they wanted a product data type as a result, when what they really needed was a sum data type.
@@cryptonative that’s a perfect case for a result or other returned value instead of an exception. It’s clunky and has needless overhead for typical control flow.
Apart from the fact that I totally fell in love with Rust too, professionally I develop in C# mostly, which is still very great language in many ways (in my opinion better than Java also), with sooo many modern features, but it also carries some legacy around as well, and exception handlers as well as the old style of inheritance based object oriented design do exist. This is not all that bad, and especially the OOP thing is basically solved already (by interfaces, extension methods, dependency injection, etc), but exceptions stay kind of a pain sometimes. And this is also acknowledged by many. But solving is not as easy. As compatibility is always a consideration as well. I sometimes wonder why so many languages made that choice actually. Why did nobody look at functional languages so much earlier. What was the actual benefit of suddenly interrupting control flow so much?
I hated this pattern before but I changed my mind recently. I've realized that in many languages people just don't care about errors at all. They don't think how to handle them, usually they just want to make the happy path work and that's all and the rest is just huge try-catch outside of their sight. Speaking of try-catch, I've heard a lot of people complain about this pattern as well... :D So, maybe people just don't like thinking about errors?
No, there is unfortunately no option type in Go, probably its most significant "missing" feature at this point. The lack of it is what makes error handling more verbose than what you would see in a language like Zig or Rust. It is far superior to a try/catch, and the compiler makes the user take explicit action to ignore it, but it definitely is not as elegant as other languages have done it.
I believe Melkey didn't understand that the author most likely meant the the go's error handling is inferior to Rust. This pattern is very common and using single character `?` instead of these three lines is a huge time saving.
Golang error handling is primitive but is still top tier. The bigger issue is nillable returns which for the most part is solvable by a comma ok, however in structs the only way to make a value nil is with a pointer, which isn’t a good solution.
My problem is with more complex error types, pattern matching, more control over reporting and replying (as api response, with easier masking or mapping), and mapping/enriching/backtracing when traversing up the call stack, etc. Rust handles that way better.
I think it’s mostly that with exceptions you tend to not handle them at all and just chuck them up to some catch block. But try properly handling a fetch call and parsing json in typescript while parsing in zod to use the actual errors, determine whether or not it was a network or parsing or server, etc. You end up with like 50 lines. Just do it once and do it properly then abstract that into a nice function that returns a single properly constructed error. You should have been doing that in the other language too. Although a short form syntax of just kicking the error up another level would be nice for like little wrapper functions and stuff where you don’t need to provide extra context. Not gonna argue there
This is silly. Go error handling is “the best”…for programmers without exposure to functional error handling, i.e. result and option types. Go cannot allow these paradigms as it is a language with a weak type system. It’s great if you’re hiring programmers with wildly different skill levels and need them to be at least a little productive without breaking too much, and I definitely think Go is a fantastic “real world” language (it’s the language I’ve written professionally the most, second being Rust), but to say Go’s error handling is “literally the best” just shows you lack experience with objectively better, strongly typed, less boilerplate-heavy-while-maintaining-clarity paradigms. Try OCaml, Rust, or Haskell in good faith. I enjoy your videos, just happen to disagree with this one.
I always tell people that you don't have to use this pattern if you don't want to. You could just panic on errors all the time and use defer with recover functions anywhere you want in upstream callstack to "catch" errors if you want a try-catch like thing. Like you said, errors are just values and you can do with them what you want in Go, just like any other values.
In my very first production system in Go which I shipped 3 weeks after discovering that there is such a language, I had a *doPanic(err error)* function that I'd call after every line that returned an error for it to panic. My very first change however was to remove one of these when I identified something I could recover from... part of my workflow required moving processed files to a location specified in a json configuration file. I was getting an error if that move was across drives. I didn't see that as a reason to panic... so I checked if that error is related to moving to a different device, in which case I'd then call a custom function that would create the destination file, copy the bytes from the source into that, call os.Stat to get attributes, call os.Chmod to write those to the destination file and along the way I check errors to determine whether or not I should proceed. At the end, I delete the source file. So now, my move functions work flawlessly and the only panic situation left is related to permissions on the file system should the system ever run into a situation in which it is not allowed to read from or write to a specific folder. And that panic hasn't even run outside of testing.
I started to learn go yesterday and knowing that is useful for writing a program faster, I prefer functions to return errors so I can know that a function has potential to failure I think go should adopt Zig error handling to attract more people to use it
When you have errors as values, you've the absolute power to handle that error as whatever the way you want. And talking about distinct error handling for each error, don't forget that in javascript try-catch, you can't put 2 different things in a same try block which can throw error because then, the catch block doesn't know what error it is handling so you then you either nest an another try-catch block or use a seperate one. I can understand why these interpreted devs gets pissed off when it comes to error handling its just because they've never done it explicitly by their own, there's always a layer of abstraction to hide things from them.
Go error handling is literally the best, its just such a simple if err != nil { }, and you can be as descriptive with the error handling as needed, sure its repetitive but its repetition is outshined by its sheer simplicity and ability to be as detailed as you want to make it
I don't even feel it as being repetitive. I use VS Code (shocking, I know) and in that, gopls adds some snippets so I only have to type *_"ife "_* and it has already inserted that code for me. And again, that's not what I want to do with the error all the time so I don't have to write it all the time.
People need to understand the difference between actually handling errors and propagating an error up the call stack (to the actual handling logic). "if err != nil" is not just something that is replaced with a try/catch block. In other languages when you call something and that spot is not the right place to handle the error, you simply let the error bubble up. When you do that, a good language should propagate the fact that the error can occur up the chain. That way you will know all the potential errors that need to be handled. Not all languages do this well. It's a mistake to fault the entire try/catch concept for flaws in how some languages implement it.
Idk why people don't simply write a helper function to assert the error. Reduces 3 lines to 1 line per function call. Or as Melkey stated, just handle it like a value and write good code.
@@sheryfhabib4060 If you just want to see if the error != nil you can do: func assertError(err error) { if err != nil { //do something } } and call that instead of writing the 3 lines over and over.
I'm concinved that the only reason you'd not like errors in Go is because you don't handle errors in other languages and the concept of error handling is new
👉I prefer 1 billion `if err != nil` THAN 1 massive try { } catch { } ... and the extra nesting level why? because it is better to know precisely the origin of the error. "Try { } catch { }" is obsolete .
I don't think repeating "errors are values" over and over helps. I don't care if errors are values or not. My problem with go's error handing is that it forces me to handle errors after each call, but I can't do that. Like, when I'm developing an API and my db is down I usually can't handle it in any other layer than in request handler or in middleware. So why should I repeat if err != nill throughout all my app layers... Also, go's error handling is too complex. It takes days of research to figure out how to actually deal with errors in such way that enables you to actually investigate and deal with production issues. Languages with exceptions make that super easy - you usually just read one documentation page and logging libraries automatically handle exceptions in http middleware
The basic problem with Rob Pike’s explanation is that the coder is at fault for not understanding Go’s error value. Instead of the workman [sic] blaming his or her tools, the tool is now blaming the worker! Personally, I can’t stand the pattern. I don’t care if it’s “little used”, as the Go team says. It’s just a ridiculous requirement. “Oh, you must handle the error as a regular value!” Since when? And why? It’s a special value that communicates something. There are easier ways of handling an error (try blocks, like many other languages have?), and there are less verbose ways of handling errors. Quite frankly, Rob Pike’s “explanation” always seemed to me to be a condescending, “Oh, you just don’t understand!” And not a little bit of him using his considerable intellect to justify a mistake.
So having control over error handling implies that some kind of default behavior or short-hand syntax are entirely ruled out? Sounds a bit religious, to be honest.
To be honest, my issue is that this is just fugly. Typing is not an issue for me, I just loathe the way this looks. I want to declare I'm returning something positive, not negative. I want my errors to be the second thing I think about, not the first. If you have prettier ways of handling this on Go, please make a video on it. Someday soon I'll learn it and I'd like it to look at something that I feel like seeing in the morning instead of regretting that I woke up.
This is just brain rot from the "never-nester" crowd. I prefer only returning at one point. ``` err:=foo(); if err != nil { err = bar() } if err != nil { err = baz() } return err
I doesn't really see what the big deal here with it like if it work for you then good for you. Personally I have no issue with the guard clause technically depend on the situation i will change my mind around that problem.
@@tranquangthang8897 i meant about people that don't like checking then returning on error, you can just check before calling and only returning at the end of the function.
@@BogdanTheGeek Good luck debugging this kind code a month after you have written it. "Ah the error happend here ... Oh wait the actual error was earlier, but that information got lost ... Oh no, it was even earlier."
Not specific to Go but being able to know that a function can possibly error helps quite a bit. Lots of times I've written python code where I forget that reading a file or connecting to a database can fail. You can say skill issue ofc but having a red squiggly line pop up on your editor while your typing just does something to your brain. With something like python you have to remember that something can throw an error/exception
This 100%. I find that in Golang I'm prompted to handle errors, but in other languages I often trip into them at runtime during a test, and *only then* realize I need to handle them.
I think the larger problem is that most people don't want to think granularly about "what should I do if this thing errors?" And instead have a giant try catch block at the top level and never think about it. So skill issue?
They only want to think about the happy path and assume that everything works just the way it should be and (big) if something happens they just want catch block will take care of that. Yeah skill issue 😂😂
@@user-gs3lm7gt5e that's how you implement stuff, 1st iteration you make it work (happy path), and other iterations are refactoring + error handling. That is why in rust you do .unwrap() and later on on 3rd iteration or so you have to replace all unwraps with error handling
Most people would agree who have tried RUST is that errors as Option/Result is great.
Oh yeah. I appreciate Go's error as values versus Try / Catch style approaches. I use to think that was the absolute best way to handle errors. Then Rust came along and I was blown away. I didn't get it at first, but after a while of actually using it in practice, it's my personal favorite way of error handling by far.
Not to say that Go doesn't have a host of benefits over Rust. At this point of using both, it's almost apples to oranges comparison wise. I use them for different use cases, despite having overlapping purposes. It's really strange.
@@InnsmouthAdmiralYeah, Rust error handling is also my favorite ways of handling errors.
The thing I don't like about Rust is you need third party crates for error handling (thiserror/anyhow)
@@rosehogenson1398 you don't need them
@@rosehogenson1398 you don’t need them, but they make it a little easier.
I quite like the syntax, because go actively reminds you that an error may happen and let's you choose whether or not you want to handle it. In Exception based languages, if you want to do robust error handling, you end up with the same amount, if not more boiler plate, it's just that these languages let you ignore it by default, whereas Go makes you think about whether to ignore it or not
I love the syntax too
Exceptions allow for centralized error handling, which most of the time is what you want. Even in most go programs, you don't handle each error individually, you just "return err". Exceptions also allow you to handle different TYPES of errors differently. This is technically also possible in errors as values, but it's only possible in go when a package provides functions for it, such as "os.IsNotExist", which is totally insane to me. Not to mention that go errors don't provide stack traces. The amount of time I wasted when I had problems with go programs and had to search for where the error I found in the logs actually occurs is unbelievable.
I actually chose Go for my current project because of the error handling. I’m a senior Java developer in my day job but returning errors from a function is so much better than having exceptions thrown at you from 4 levels down in the call stack! I absolutely love the Rust error handling but the rest of the language is just too complex. I did quite a lot of programming in Rust and the thing is Go is the language that gets out of my way. I never have to fight it! I can just get shit done!
I would still have loved an Option type in Go or the question mark operator from Rust that would basically let you return the error if thrown if the error types are the same without the if err ≠ nil thing. But hey, there’s no perfect language.
Oh and enums! For the love of God why doesn’t Go have at least basic enums!? And no…iota sucks. Still using Go though… 😂
Well, there's Zig... lol. But yeah, that makes tons of sense. Rust is just too much.
I'm a senior .NET developer... I feel the same way. Rust looks great, but I'm not very productive with it. Go's simplicity is great.
Every javascript or python programmer goes why do I have to write this every time because they used to not handling errors. I like this because Golang you know what could error by using the API or libraries you are using. You are force to think about what do you want to do if that thing error
If you're not adding additional context to your error by wrapping you're not handling errors correctly in Go. This context can also make the code more self-documenting.
That being said, it would be nice to have Zig style error handling in Go.
Back in my C# days, I'd get really lazy and do a general try-catch loop and log the exception message. It never really got me to think about types of errors, and really how to handle them based on what the actual error is. At first I was annoyed by the Go approach, but over time it's made me think more about the operations my functions do and how they could fail. Ultimately it has made me a much more thoughtful developer.
I could not agreee more!
I think it's mostly we'd like syntax sugar.
err := foo() // base where you need to manually handle it.
! := foo() //panic error
? := foo() //zero all other values in return except for error
I think they should adopt it to bring more people to use go. I'm pretty sure there are many people who like go philosophy, but hate if err
I think this pattern is great. Yes, I have to write a few more characters but it's not a big deal. I like that I get more granular control, not a huge "try"messy blob.
Yeah, everything is better that Javascript's error handling.
The issue is that over time, in really big projects, that few characters end up being 70% of the code base. When all you need is a simple "stop the world, and report". Especially with web projects where loads of content is simply reading content. All that can be solved with a one liner or a "try" function, or a rust ? but yea ... For some reason the Go dev think that people will not be able to handle that much "work".
Try/catch isn't really a whole lot different. It's just arranged in a different manner. People are making way too big a deal out of both paradigms.
this is a nice video ! I was hoping you could show us different ways to handle errors in Go. Maybe there's another video about it? I hope so.
Thank you for this!
While I agree with everything, what I'm missing in Go is a native way to wrap errors with types / by opinionated about using them.
I know you can implement the behavior yourself, what I wanted to ask is - do you have a method you normally use? Or do you just use them as strings?
I typically wrap them or bubble them up with fmt.Errorf
Better than exceptions, sure. I still want a proper Result type tho
I just created a few snippets for the common error handling patterns, it is not as bad as Twitter makes it seem. You know what is more annoying is surrounding multiple try/catch statements in async/await JS
Thanks for your video!!! Just started playing with Go this week and I like it. I like the fact that errors are values, it has always been a mess for me to deal with errors in typescript.
The fact is that
foo, err := bar()
if err != nil {
return err
}
could just be replaced with this small syntactic sugar:
foo := bar()?
I really don't know why they didn't already do this.
What about stacktraces, the absence of them doesn't make the application undebuggable when an error occurs in a deployed env?
Yes, but you are able to identify if you wrap your error up
Usually, when you have a function func foo() (int, error), you want to express the fact EITHER foo returns an int OR it returns an error. But with the way Go works, nothing prevents foo to return two nil values or two non nil values.
I feel like it is a very small downside to Golang's error handling (fixed by convention: checking if err is nil) and that's why I like Rust's error handling more.
This is my only complaint with it. On the other hand, maybe having an error and some kind of value is fine. Both being nil seems like a user error, though. Documentation should describe the behavior better than convention, imo.
I think the Result variant model is safer from an error handling perspective, but it is more opinionated. Even in rust, error handling is sort of optional given you don’t have to use it and you can always unwrap if it’s from third party code.
There are cases where it is a valid thing, returning foo *AND* an error. I managed to read 2,753 bytes then an error happened. Error might be network location became unavailable, tried to read past the end of a file, file got deleted while reading, and so much more. Returning both makes sense in those scenarios. You get the data that was read and whatever else happened. Being values, the error can be used in program flow. I know to stop reading if I get the *EOF* error. And the fact that I got an *EOF* won't invalidate whatever data I have in my buffer.
That is never the problem ever
Hi, Melkey. How long have you been working with Golang? And how long did it take you to consider yourself proficient in the technology? I've been working with Golang for 6 months now (junior developer), and even though I study every day, I still don't feel very prepared.
Yeah, ive been using go professionally for around 2 years now.
It def takes some time to get used to
Error handling: Zig/Rust > Go > shit > exception/try/catch
This guy gets it. Love Go, and have been using a lot of Zig lately, and error handling in it solves the minor annoyances of Go's verbosity in error handling, while keeping its strengths in making the user *explicitly* either handle/ignore it. I am not very familiar with Rust, but my understanding is that both it and Zig are similar in how they handle errors.
yoooooo. another great vid Melkey
Shout out SnowTheParrot
As someone who comes from JS/TS world into Go - I really like the Go way of handling errors. It forces me to think about extra edge cases which I haven't even been thinking about in the JS world and this "enforces" me to write a higher quality software.
error handling in go is annoying, copilot kinda helps in this regard, but would you rather have a program that crashes every time an error happens inside a function? the alternative is sometimes catching errors, sometimes not, depending on how much you trust your function.
The greatest trick Rob Pike ever pulled was convincing Go programmers that they wanted a product data type as a result, when what they really needed was a sum data type.
the problem is not the boilerplate but that it doesn't panic by default if there is an error. that's prone to bugs
Not all errors warrant a panic.
@@TehKarmalizer those that shouldn’t panic you catch them and provide an alternative
@@cryptonative that’s a perfect case for a result or other returned value instead of an exception. It’s clunky and has needless overhead for typical control flow.
@@TehKarmalizer i think result is great. that’s what i said: a result panics when unwraped
Compared to Java and others go has better error handling... However rust's result type is too damn good even compared to go way of doing things
Apart from the fact that I totally fell in love with Rust too, professionally I develop in C# mostly, which is still very great language in many ways (in my opinion better than Java also), with sooo many modern features, but it also carries some legacy around as well, and exception handlers as well as the old style of inheritance based object oriented design do exist.
This is not all that bad, and especially the OOP thing is basically solved already (by interfaces, extension methods, dependency injection, etc), but exceptions stay kind of a pain sometimes. And this is also acknowledged by many. But solving is not as easy. As compatibility is always a consideration as well.
I sometimes wonder why so many languages made that choice actually. Why did nobody look at functional languages so much earlier. What was the actual benefit of suddenly interrupting control flow so much?
Rust has the best error handling imho, but it can get quite overwhelming sometimes.
I hated this pattern before but I changed my mind recently. I've realized that in many languages people just don't care about errors at all. They don't think how to handle them, usually they just want to make the happy path work and that's all and the rest is just huge try-catch outside of their sight. Speaking of try-catch, I've heard a lot of people complain about this pattern as well... :D So, maybe people just don't like thinking about errors?
Yeah, thats probably it.
Which is why I really love how the creators of Go just handle errors, just like any regular value
1:50 this code CALLS for some sort of "null coalescing operator", or option, to hide the repetition. Does go have something like that?
No, there is unfortunately no option type in Go, probably its most significant "missing" feature at this point. The lack of it is what makes error handling more verbose than what you would see in a language like Zig or Rust. It is far superior to a try/catch, and the compiler makes the user take explicit action to ignore it, but it definitely is not as elegant as other languages have done it.
kudos to lazygit dev, great peace of software! love it.... also absolutely love golang error handling :)
I totally agree, furthermore, working with go made me rethink the way I handle exceptions in other languages
Hell yeah
Copium, I have come to appreciate Result as the best error handling implementation I've ever used.
Good vid like usual
Nice
I believe Melkey didn't understand that the author most likely meant the the go's error handling is inferior to Rust. This pattern is very common and using single character `?` instead of these three lines is a huge time saving.
Golang error handling is primitive but is still top tier. The bigger issue is nillable returns which for the most part is solvable by a comma ok, however in structs the only way to make a value nil is with a pointer, which isn’t a good solution.
Where result?
My problem is with more complex error types, pattern matching, more control over reporting and replying (as api response, with easier masking or mapping), and mapping/enriching/backtracing when traversing up the call stack, etc. Rust handles that way better.
Error handling looks bad now, but it still better that try-catch :D
Maybe it would be great just pass out error with some syntax sugar
I love Golang error handling.
Exists one more painful moment - null pointers, really dissapointment thing
I think it’s mostly that with exceptions you tend to not handle them at all and just chuck them up to some catch block. But try properly handling a fetch call and parsing json in typescript while parsing in zod to use the actual errors, determine whether or not it was a network or parsing or server, etc. You end up with like 50 lines.
Just do it once and do it properly then abstract that into a nice function that returns a single properly constructed error. You should have been doing that in the other language too.
Although a short form syntax of just kicking the error up another level would be nice for like little wrapper functions and stuff where you don’t need to provide extra context. Not gonna argue there
Idk i like being explicit about it. Seems fine to me !
This is silly. Go error handling is “the best”…for programmers without exposure to functional error handling, i.e. result and option types. Go cannot allow these paradigms as it is a language with a weak type system. It’s great if you’re hiring programmers with wildly different skill levels and need them to be at least a little productive without breaking too much, and I definitely think Go is a fantastic “real world” language (it’s the language I’ve written professionally the most, second being Rust), but to say Go’s error handling is “literally the best” just shows you lack experience with objectively better, strongly typed, less boilerplate-heavy-while-maintaining-clarity paradigms. Try OCaml, Rust, or Haskell in good faith.
I enjoy your videos, just happen to disagree with this one.
Now try finding a job with ocaml, rust, or haskell. These neckbeard arguments don't work in the real world.
This is literally solved with Rust's "?", it holds the same syntactical meaning as this whole pattern, and only takes a single byte
I should really try out Rust more seriously
I always tell people that you don't have to use this pattern if you don't want to. You could just panic on errors all the time and use defer with recover functions anywhere you want in upstream callstack to "catch" errors if you want a try-catch like thing.
Like you said, errors are just values and you can do with them what you want in Go, just like any other values.
In my very first production system in Go which I shipped 3 weeks after discovering that there is such a language, I had a *doPanic(err error)* function that I'd call after every line that returned an error for it to panic. My very first change however was to remove one of these when I identified something I could recover from... part of my workflow required moving processed files to a location specified in a json configuration file. I was getting an error if that move was across drives. I didn't see that as a reason to panic... so I checked if that error is related to moving to a different device, in which case I'd then call a custom function that would create the destination file, copy the bytes from the source into that, call os.Stat to get attributes, call os.Chmod to write those to the destination file and along the way I check errors to determine whether or not I should proceed. At the end, I delete the source file. So now, my move functions work flawlessly and the only panic situation left is related to permissions on the file system should the system ever run into a situation in which it is not allowed to read from or write to a specific folder. And that panic hasn't even run outside of testing.
I started to learn go yesterday and knowing that is useful for writing a program faster, I prefer functions to return errors so I can know that a function has potential to failure
I think go should adopt Zig error handling to attract more people to use it
Whatever how go's error handling is ,I prefer that rather than dealing with result types of rust
I prefer it over try and catch, thats for sure
When you have errors as values, you've the absolute power to handle that error as whatever the way you want.
And talking about distinct error handling for each error, don't forget that in javascript try-catch, you can't put 2 different things in a same try block which can throw error because then, the catch block doesn't know what error it is handling so you then you either nest an another try-catch block or use a seperate one.
I can understand why these interpreted devs gets pissed off when it comes to error handling its just because they've never done it explicitly by their own, there's always a layer of abstraction to hide things from them.
watching stream just now..
How was the stream!
I used to believe Go had the best system of handling errors
Make a video on how to handle errors on go properly
It's not bad but better if there was a way to force users of my api to handle them or at least ignore them explicitly.
before I used go it looked giga annoying, in practice it's one of the top things about go
I like the err handling.
CRÈME DE LA CRÈME indeed...
Go is the best
Go error handling is literally the best, its just such a simple if err != nil { }, and you can be as descriptive with the error handling as needed, sure its repetitive but its repetition is outshined by its sheer simplicity and ability to be as detailed as you want to make it
I don't even feel it as being repetitive. I use VS Code (shocking, I know) and in that, gopls adds some snippets so I only have to type *_"ife "_* and it has already inserted that code for me. And again, that's not what I want to do with the error all the time so I don't have to write it all the time.
People need to understand the difference between actually handling errors and propagating an error up the call stack (to the actual handling logic). "if err != nil" is not just something that is replaced with a try/catch block. In other languages when you call something and that spot is not the right place to handle the error, you simply let the error bubble up. When you do that, a good language should propagate the fact that the error can occur up the chain. That way you will know all the potential errors that need to be handled. Not all languages do this well. It's a mistake to fault the entire try/catch concept for flaws in how some languages implement it.
I like go's error handling
One line, like "if err != nil return err" would be nice :/
It would be nice
OHHHHHHHH BOUYYYY DON'T YOU...
Idk why people don't simply write a helper function to assert the error. Reduces 3 lines to 1 line per function call. Or as Melkey stated, just handle it like a value and write good code.
please can you explain this better?
@@sheryfhabib4060 If you just want to see if the error != nil you can do:
func assertError(err error) {
if err != nil {
//do something
}
}
and call that instead of writing the 3 lines over and over.
All my homies like go error handling
I'm concinved that the only reason you'd not like errors in Go is because you don't handle errors in other languages and the concept of error handling is new
👉I prefer 1 billion `if err != nil` THAN 1 massive try { } catch { } ... and the extra nesting level
why? because it is better to know precisely the origin of the error. "Try { } catch { }" is obsolete .
I don't think repeating "errors are values" over and over helps. I don't care if errors are values or not. My problem with go's error handing is that it forces me to handle errors after each call, but I can't do that. Like, when I'm developing an API and my db is down I usually can't handle it in any other layer than in request handler or in middleware. So why should I repeat if err != nill throughout all my app layers...
Also, go's error handling is too complex. It takes days of research to figure out how to actually deal with errors in such way that enables you to actually investigate and deal with production issues. Languages with exceptions make that super easy - you usually just read one documentation page and logging libraries automatically handle exceptions in http middleware
Error bubbling and wrapping
The basic problem with Rob Pike’s explanation is that the coder is at fault for not understanding Go’s error value. Instead of the workman [sic] blaming his or her tools, the tool is now blaming the worker!
Personally, I can’t stand the pattern. I don’t care if it’s “little used”, as the Go team says. It’s just a ridiculous requirement. “Oh, you must handle the error as a regular value!” Since when? And why? It’s a special value that communicates something. There are easier ways of handling an error (try blocks, like many other languages have?), and there are less verbose ways of handling errors.
Quite frankly, Rob Pike’s “explanation” always seemed to me to be a condescending, “Oh, you just don’t understand!” And not a little bit of him using his considerable intellect to justify a mistake.
Go enforce you to handle error so your program won't crash and you can't excuse forgetting to handle error.
So having control over error handling implies that some kind of default behavior or short-hand syntax are entirely ruled out? Sounds a bit religious, to be honest.
Hmm, no I dont think that is the case
To be honest, my issue is that this is just fugly. Typing is not an issue for me, I just loathe the way this looks. I want to declare I'm returning something positive, not negative. I want my errors to be the second thing I think about, not the first. If you have prettier ways of handling this on Go, please make a video on it. Someday soon I'll learn it and I'd like it to look at something that I feel like seeing in the morning instead of regretting that I woke up.
Yeah go errors are bad. I want a try catch , with 20 exceptions after each function.
It is quite ironic that Rust fans claim Go's error handling is verbose, given their dreadful match statements
Yes, go is not ergonomic. Verbose needlessly and hard to read.
This is just brain rot from the "never-nester" crowd. I prefer only returning at one point.
```
err:=foo();
if err != nil {
err = bar()
}
if err != nil {
err = baz()
}
return err
I doesn't really see what the big deal here with it like if it work for you then good for you. Personally I have no issue with the guard clause technically depend on the situation i will change my mind around that problem.
@@tranquangthang8897 i meant about people that don't like checking then returning on error, you can just check before calling and only returning at the end of the function.
So if you get 2 errors, you are only remembering the last one here ...
@@jongeduard yes, exactly like in the example.
@@BogdanTheGeek Good luck debugging this kind code a month after you have written it. "Ah the error happend here ... Oh wait the actual error was earlier, but that information got lost ... Oh no, it was even earlier."
its a good thing the author has no idea, it's clearly a skill issue
SKILL ISSUE CONFIRMED
You are manipulative on Reddit you have 38 reasons why Golang is bad and here you say it is great you love it 👎 it was my mistake watching your videos
what the fuck are you talking about
@@MelkeyDev oh I mean 32 reasons why TS is better than Golang
Skill issues
I would love it for Go to adopt Rust's ? operator to return errors automatically for those cases where you want to propagate it as-is.
that would be really cool i think