From the very little Go I’ve written, I gotta say that the explicit if err != nil error handling struck me as something pretty darn good even if a bit verbose. And in my experience outside Go, just knowing its outlook on error handling has nudged me towards writing more satisfying error handling code, too: https://riki.house/programming/blog/try-is-not-the-only-option
I also regularly write C++ code which does error handling in this way and do not find it particularly revolting. (Though most C++ I write is very game devy, where an error usually results in a crash, or is logged and the game keeps on chugging along.)
I can see why people would not share the same opinion though. Perhaps I’m just slowly becoming a boomer.
Yeah, I think the grievance about Go boilerplate is somewhat misguided. Most of the “boilerplate” is annotating the error with context, and I’m not really aware of an easy way to alleviate this problem. Sure, a ? operator will help you if you’re just writing return err all over the place, but if that’s your default error handling approach then you’re writing substandard code.
That said, I don’t love the idea of wedding the syntax so tightly to the error type. I wish this proposal would take a more general approach so it could be used for functions that return T, bool as well (roughly Go’s way of spelling Option<T>), for example.
You can also add stacktraces to errors early. Then you can just return error and don’t need to rely on grepping (hopefully) unique (they are not) error strings to reconstruct a stacktrace by hand.
The problem with the Go error form is not the syntax. It’s the fact that, by using this error-handling form, the Go compiler is basically not involved in enforcing the correctness of your program.
Go will fail to compile if you have an unused import, but you can just forget to check an error result. That’s the problem.
you can just forget to check an error result. That’s the problem.
I agree with you that it’s a more serious problem than the boilerplate, but the overwhelming majority of complaints about Go are about the boilerplate. That said, “you can just forget to check an error result” is also not a particularly serious problem in practice. I’m sure it has lead to bugs in the past, but these problems are relatively rare in practice, because:
the errcheck linter exists and is bundled with popular linter aggregators
even without a linter, you still get a compiler error when you ignore the error in an assignment (e.g., file := os.Open() instead of file, err := os.Open()
for better or worse, Go programmers are pretty thoroughly conditioned to handle errors. A fallible operation without an error check looks conspicuous.
Are these as nice as having error-handling checks in the language? No. Is it a real problem in practice? No.
I think the question I would pose, then, is: does type-safety matter or doesn’t it?
If linting is sufficient to enforce program correctness, why bother with static types? Why not use a dynamic language that’s easier to work with?
If I’m accepting the effort of working within a static type system that requires me to correctly annotate all my types, then I also want the type system to take responsibility for the invariants of my program.
If I have to expend the effort of writing types but also have to write a thousand ad-hoc if statements to check my invariants, then Go feels like the worst of both worlds. At least in a dynamic language, I can build higher-level abstractions to do this in a less tedious way.
I think the question I would pose, then, is: does type-safety matter or doesn’t it?
I don’t think it’s a binary proposition. It certainly matters more in some cases than others, and I don’t think forcing you to handle errors ends up being an enormous deal in practice. Would I prefer that Go’s type system enforced handling return values? Sure. Has this ever caused me a problem in my ~15 years of extensive Go use? Not that I recall (though I’m sure it has caused someone somewhere a problem at least one time).
If I have to expend the effort of writing types but also have to write a thousand ad-hoc if statements to check my invariants, then Go feels like the worst of both worlds.
Eh, most of the boilerplate with error handling is in annotating the errors with helpful context, which, as far as I know, doesn’t lend itself well to an automated solution unless your solution is not to annotate at all (in which case you’re just trading a little pain up front for more pain at debug time) or to annotate with stack traces or something similarly painful to consume.
It’s also not implemented well. It requires observing the difference between defining err and re-assigning err, which is important only because go complected error handling with variable definitions, and uses boilerplate that can’t always limit the variable’s scope to just the scope it needs.
When moving code around or temporarily commenting out parts of it, it forces adjusting the syntax. Sometimes reassignment isn’t possible, and you get err2 too, and a footgun of mixing it up with the first err. This problem doesn’t have to exist.
Brad Fitzpatrick made a point about this somewhere… I decided to keep a copy for posterity. It’s ugly, no one should use it. But exposes the issue you put forward of ignored errors.
Go will fail to compile if you have an unused import, but you can just forget to check an error result. That’s the problem.
I did notice that, and totally agree. I’d probably expand that to error out on any unused values overall, not just errors, but at this point it’s probably too big of a breaking change to make it into the compiler itself.
You’re comparing it to the wrong thing. The ? propagation is a revolt against C++ style exceptions too:
Throwing and catching is an alternative parallel way of “returning” values from functions. ? keeps returning regular values in a normal way.
Exceptions are invisible at the call site. ? keeps the error handling locally visible.
C++-style exceptions are even invisible in function’s prototype, and Java’s typed exceptions aren’t liked either. ? simply uses normal function return types, keeping the error type explicit and easy to find.
Exceptions can unwind past many levels of the call stack. ? keeps unwinding one call at a time.
? is closer to golang’s philosophy than any other error handling strategy. It agrees that error handling should be locally explicit and based on regular values. It just doesn’t agree that the explicitness needs to go as far as taking 3 lines of almost identical code every time.
Experience from Rust shows that just a single char is sufficiently explicit for all the boring cases, and because the errors are just values, all the non-trivial cases can still be handled with normal code.
It just doesn’t agree that the explicitness needs to go as far as taking 3 lines of almost identical code every time.
I usually want to add context to my errors, so the 3 lines are rarely “almost identical”. Do people routinely omit additional context in Rust, or does the ? somehow allow for more succinct annotations than what we see in Go? As far as I can tell, it seems like the ? operator is only useful in the ~5% of cases where I want to do nothing other than propagate an unannotated error, but people are making such a big fuss about it that I’m sure I’m misunderstanding something.
? calls a standard From trait that converts or wraps the error type you’re handling into the error type your function returns, and the conversion can can have a custom implementation. There’s a cottage industry of macro helpers that make these mappings easy to define.
It works well with Rust’s enums, e.g. if your function returns my::ConfigFileError, you can make std::io::Error convert to ConfigFileError::Io(cause), and another type to ConfigFileError::Syntax(parse_error). Then another function can convert that config error into its own ServerInitError::BecauseConfigFailed(why), and so on. That handles ~80% of cases.
For other cases there are helper functions on Result, like .map_err(callback) that run custom code that modifies the error type. The advantage is that this is still an expression and chains nicely:
let x = do().map_err(Custom::new)?
.do_more().context(obj)?
.etc().with_context(callback)?;
And for complex cases there’s always match or if let Err(err) that is like golang’s approach.
The go codebases that I work with are very often just return nil, err, and at best return nil, custom.Wrap(err) which is like the From::from(err) that ? calls.
Thanks, I am aware of these but you summarized them well. I guess my feeling is that this largely moved the annotation boilerplate into creating a new error type. This doesn’t seem to me to be an enormous net win if at all. In my experience, creating new error types can be quite burdensome, at least if you want to do a good, idiomatic job of it (IIRC, when I used some of the macro libraries, they would throw difficult-to-debug error messages). I may have been holding it wrong, but with Go I can just return fmt.Errorf(…) and move on with life. That’s worth a lot more to me than the absolute lowest character count. 🤷♂️
fmt.Errof isn’t strongly typed. bail!("fmt") does that in Rust, and that’s okay for small programs, but libraries typically care to return precise types that allow consumers of the library to perform error recovery, internationalisation, etc.
You’re right that it moves boilerplate to type definitions. I like that, because that boilerplate is concentrated in its own file, instead of spread thinly across the entire codebase.
fmt.Errorf isn’t strongly typed. bail!(“fmt”) does that in Rust, and that’s okay for small programs, but libraries typically care to return precise types that allow consumers of the library to perform error recovery, internationalisation, etc.
I agree, and in Go we only use fmt.Errorf() if we are annotating an error. Error recovery works fine, because Go error recovery involves peeling away the annotations to get at the root error. This is probably not ideal, but it’s idiomatic and doesn’t cause me any practical problems whereas with Rust I have to choose between being un-idiomatic (and bridging my personal idiom with idioms used by my dependencies), or writing my own error types for annotation purposes, or using a macro library to generate error types (and dealing with the difficult-to-debug macro errors) all of which involve a pretty high degree of tedium/toil. I don’t love the Go solution, but it mostly gets out of my way, and I haven’t figured out how to make Rust’s error handling get out of my way. :/
You’re right that it moves boilerplate to type definitions. I like that, because that boilerplate is concentrated in its own file, instead of spread thinly across the entire codebase
Yeah, I agree that making dedicated error types makes sense when you are reusing errors across the codebase but for simply annotating errors we are almost always concerned with a one-off error so there’s no “spread thinly across the entire codebase” to worry about.
I’m not trying to be a Go fanboy here; I don’t particularly like Go’s error handling, but for all its warts and oddity, it mostly gets out of my way. I feel like I spend at least an order of magnitude less time meddling with errors in Go than I do in Rust, even though Rust has ? (my constraint is almost never keystrokes). My issues with Go are mostly theoretical or philosophical, while my issues with Rust are regrettably practical. :(
I usually want to add context to my errors, so the 3 lines are rarely “almost identical”. Do people routinely omit additional context in Rust, or does the ? somehow allow for more succinct annotations than what we see in Go?
You’d usually do something like .context(/* error context here */)? in such cases. Though, to be honest, while I’m not a Go programmer, I’ve seen some Go code, and it seems most projects don’t add context to errors in most cases?
Personally I haven’t found the need to add context to errors in Rust anywhere close to 95% of the time. Usually a stacktrace has already been captured and there isn’t much to add.
Though, to be honest, while I’m not a Go programmer, I’ve seen some Go code, and it seems most projects don’t add context to errors in most cases?
It seems to vary a lot, and especially older projects (before the fmt.Errorf() stuff was added) probably don’t attach context.
Personally I haven’t found the need to add context to errors in Rust anywhere close to 95% of the time. Usually a stacktrace has already been captured and there isn’t much to add.
Usually I want to add identifiers (e.g., filepaths, resource identifiers, etc) to errors, so rather than “permission denied”, you get “opening /foo/baz.txt: permission denied”. I also haven’t found a very satisfying way to attach stack traces to errors–do you check each call site to determine whether it has already attached the stack trace? Maybe that’s reasonable, but what I usually do is make sure each function adds an annotation that says what it’s doing (e.g., OpenFile() will annotate its errors with fmt.Errorf("opening file %s: %w", path, err)). I definitely don’t think that’s an ideal solution; it’s just the best one I’ve found so far. 🤷♂️
My hope is this doesn’t go through, it’s merely a syntactic sugar that unfortunately introduces more questions than it answers. The comments bring up a lot of real issues with zero-or-not value, automatic err variable declaration, etc.
I can think of others edge cases too, like functions that return a concrete type that happen to implement the error interface, or returning the error at different positions in the tuple. These questions shouldn’t be ignored, semantic concerns should trump syntax.
The real problem is that error handling is not statically enforced. If that won’t change I see no reason to reduce boilerplate by one line.
I’m usually very critical of error handling proposals, but I really like this one. It keeps the spirit of current error handling instead of trying to replace it. It does look a bit weird on first sight but I easily can imagine getting used to it.
I’m not a big fan of the automatic err variable declaration though.
Edit: reading more into it, I don’t like the automatic return when ? is not followed by a block.
func Run() error {
Start() ? // returns error from Start if not nil
Wait() ? // returns error from Wait if not nil
return nil
}
This example is too far from current Go idioms, visually (without reading it) I thought it was an interface declaration. I wish they would keep explicit err return like this:
This is a very confusing proposal and problem. When I write go, I’m more concerned I have to rely on checked casts just to know if the err I have is what I think it is and I can never guarantee I have an exhaustive set of branches for every possible (possibly even nested and wrapped) error. I don’t see how sugaring over:
err := something()
if err != nil {
...
}
really solves the biggest problem I see and I can’t imagine if err != nil is a struggle for many.
This can’t land fast enough. if err != nil reads simple on its face, but has always felt extremely clunky and error prone, and comes with an air of “well simply don’t forget to check for nil here!” It’s one of many reasons I’ve never enjoyed writing Go and have joked that it’s a world-class ecosystem and toolchain lacking only a decent language.
Changing all return signatures of the Go ecosystem would be a fatally breaking change, so at least reducing the boilerplate to make the existing signatures more ergonomic (and maybe a bit less error prone) feels like a huge positive to me.
OK, interesting. I was gonna dismiss this as one of the thousand “let’s put a new syntax on an idea that has been suggested many times” proposals, but this one is by Ian Lance Taylor, a member of the Go Team.
It would be convenient for functions that return (result, err) pairs if ? with no block returned zero for the result and passed through the err.
This proposal mentions a separate one to allow writing return ..., err instead of return result, err, but I don’t see any examples suggesting that’s going to kick in automatically for ? with no block. The case for adding that behavior is just this occurs a lot and this would make it more concise. I imagine the case against has to do with complexity or the potential for mistakes.
If the argument is mostly about implementation difficulty, I hope it’d be considered for addition later if it doesn’t make the initial implementation.
I find midlang to perfectly describe the ethos of Go. Everything in it is perfectly so-so, with the language trying really hard to prevent anyone from coming up with anything “too smart” in an name of avoiding all the possible bad uses.
Costed me some dowvotes, but it’s true. :D . And I will be surprised if a community will be happy about a weird, unconventional error handling operator. Though … it is kid of mid too… so maybe?
From the very little Go I’ve written, I gotta say that the explicit
if err != nilerror handling struck me as something pretty darn good even if a bit verbose. And in my experience outside Go, just knowing its outlook on error handling has nudged me towards writing more satisfying error handling code, too: https://riki.house/programming/blog/try-is-not-the-only-optionI also regularly write C++ code which does error handling in this way and do not find it particularly revolting. (Though most C++ I write is very game devy, where an error usually results in a crash, or is logged and the game keeps on chugging along.)
I can see why people would not share the same opinion though. Perhaps I’m just slowly becoming a boomer.
Yeah, I think the grievance about Go boilerplate is somewhat misguided. Most of the “boilerplate” is annotating the error with context, and I’m not really aware of an easy way to alleviate this problem. Sure, a
?operator will help you if you’re just writingreturn errall over the place, but if that’s your default error handling approach then you’re writing substandard code.That said, I don’t love the idea of wedding the syntax so tightly to the error type. I wish this proposal would take a more general approach so it could be used for functions that return
T, boolas well (roughly Go’s way of spellingOption<T>), for example.You can also add stacktraces to errors early. Then you can just
return errorand don’t need to rely on grepping (hopefully) unique (they are not) error strings to reconstruct a stacktrace by hand.The problem with the Go error form is not the syntax. It’s the fact that, by using this error-handling form, the Go compiler is basically not involved in enforcing the correctness of your program.
Go will fail to compile if you have an unused import, but you can just forget to check an error result. That’s the problem.
I agree with you that it’s a more serious problem than the boilerplate, but the overwhelming majority of complaints about Go are about the boilerplate. That said, “you can just forget to check an error result” is also not a particularly serious problem in practice. I’m sure it has lead to bugs in the past, but these problems are relatively rare in practice, because:
errchecklinter exists and is bundled with popular linter aggregatorsfile := os.Open()instead offile, err := os.Open()Are these as nice as having error-handling checks in the language? No. Is it a real problem in practice? No.
I think the question I would pose, then, is: does type-safety matter or doesn’t it?
If linting is sufficient to enforce program correctness, why bother with static types? Why not use a dynamic language that’s easier to work with?
If I’m accepting the effort of working within a static type system that requires me to correctly annotate all my types, then I also want the type system to take responsibility for the invariants of my program.
If I have to expend the effort of writing types but also have to write a thousand ad-hoc if statements to check my invariants, then Go feels like the worst of both worlds. At least in a dynamic language, I can build higher-level abstractions to do this in a less tedious way.
I don’t think it’s a binary proposition. It certainly matters more in some cases than others, and I don’t think forcing you to handle errors ends up being an enormous deal in practice. Would I prefer that Go’s type system enforced handling return values? Sure. Has this ever caused me a problem in my ~15 years of extensive Go use? Not that I recall (though I’m sure it has caused someone somewhere a problem at least one time).
Eh, most of the boilerplate with error handling is in annotating the errors with helpful context, which, as far as I know, doesn’t lend itself well to an automated solution unless your solution is not to annotate at all (in which case you’re just trading a little pain up front for more pain at debug time) or to annotate with stack traces or something similarly painful to consume.
It’s also not implemented well. It requires observing the difference between defining
errand re-assigningerr, which is important only because go complected error handling with variable definitions, and uses boilerplate that can’t always limit the variable’s scope to just the scope it needs.When moving code around or temporarily commenting out parts of it, it forces adjusting the syntax. Sometimes reassignment isn’t possible, and you get
err2too, and a footgun of mixing it up with the firsterr. This problem doesn’t have to exist.Brad Fitzpatrick made a point about this somewhere… I decided to keep a copy for posterity. It’s ugly, no one should use it. But exposes the issue you put forward of ignored errors.
https://go.dev/play/p/JBQ3zeVMti For your amusement.
I did notice that, and totally agree. I’d probably expand that to error out on any unused values overall, not just
errors, but at this point it’s probably too big of a breaking change to make it into the compiler itself.You’re comparing it to the wrong thing. The
?propagation is a revolt against C++ style exceptions too:Throwing and catching is an alternative parallel way of “returning” values from functions.
?keeps returning regular values in a normal way.Exceptions are invisible at the call site.
?keeps the error handling locally visible.C++-style exceptions are even invisible in function’s prototype, and Java’s typed exceptions aren’t liked either.
?simply uses normal function return types, keeping the error type explicit and easy to find.Exceptions can unwind past many levels of the call stack.
?keeps unwinding one call at a time.?is closer to golang’s philosophy than any other error handling strategy. It agrees that error handling should be locally explicit and based on regular values. It just doesn’t agree that the explicitness needs to go as far as taking 3 lines of almost identical code every time.Experience from Rust shows that just a single char is sufficiently explicit for all the boring cases, and because the errors are just values, all the non-trivial cases can still be handled with normal code.
I usually want to add context to my errors, so the 3 lines are rarely “almost identical”. Do people routinely omit additional context in Rust, or does the
?somehow allow for more succinct annotations than what we see in Go? As far as I can tell, it seems like the?operator is only useful in the ~5% of cases where I want to do nothing other than propagate an unannotated error, but people are making such a big fuss about it that I’m sure I’m misunderstanding something.Rust solves this without need to abandon
?.?calls a standardFromtrait that converts or wraps the error type you’re handling into the error type your function returns, and the conversion can can have a custom implementation. There’s a cottage industry of macro helpers that make these mappings easy to define.It works well with Rust’s enums, e.g. if your function returns
my::ConfigFileError, you can makestd::io::Errorconvert toConfigFileError::Io(cause), and another type toConfigFileError::Syntax(parse_error). Then another function can convert that config error into its ownServerInitError::BecauseConfigFailed(why), and so on. That handles ~80% of cases.For other cases there are helper functions on
Result, like.map_err(callback)that run custom code that modifies the error type. The advantage is that this is still an expression and chains nicely:And for complex cases there’s always
matchorif let Err(err)that is like golang’s approach.The go codebases that I work with are very often just
return nil, err, and at bestreturn nil, custom.Wrap(err)which is like theFrom::from(err)that?calls.Thanks, I am aware of these but you summarized them well. I guess my feeling is that this largely moved the annotation boilerplate into creating a new error type. This doesn’t seem to me to be an enormous net win if at all. In my experience, creating new error types can be quite burdensome, at least if you want to do a good, idiomatic job of it (IIRC, when I used some of the macro libraries, they would throw difficult-to-debug error messages). I may have been holding it wrong, but with Go I can just return fmt.Errorf(…) and move on with life. That’s worth a lot more to me than the absolute lowest character count. 🤷♂️
fmt.Errofisn’t strongly typed.bail!("fmt")does that in Rust, and that’s okay for small programs, but libraries typically care to return precise types that allow consumers of the library to perform error recovery, internationalisation, etc.You’re right that it moves boilerplate to type definitions. I like that, because that boilerplate is concentrated in its own file, instead of spread thinly across the entire codebase.
I agree, and in Go we only use
fmt.Errorf()if we are annotating an error. Error recovery works fine, because Go error recovery involves peeling away the annotations to get at the root error. This is probably not ideal, but it’s idiomatic and doesn’t cause me any practical problems whereas with Rust I have to choose between being un-idiomatic (and bridging my personal idiom with idioms used by my dependencies), or writing my own error types for annotation purposes, or using a macro library to generate error types (and dealing with the difficult-to-debug macro errors) all of which involve a pretty high degree of tedium/toil. I don’t love the Go solution, but it mostly gets out of my way, and I haven’t figured out how to make Rust’s error handling get out of my way. :/Yeah, I agree that making dedicated error types makes sense when you are reusing errors across the codebase but for simply annotating errors we are almost always concerned with a one-off error so there’s no “spread thinly across the entire codebase” to worry about.
I’m not trying to be a Go fanboy here; I don’t particularly like Go’s error handling, but for all its warts and oddity, it mostly gets out of my way. I feel like I spend at least an order of magnitude less time meddling with errors in Go than I do in Rust, even though Rust has
?(my constraint is almost never keystrokes). My issues with Go are mostly theoretical or philosophical, while my issues with Rust are regrettably practical. :(You’d usually do something like
.context(/* error context here */)?in such cases. Though, to be honest, while I’m not a Go programmer, I’ve seen some Go code, and it seems most projects don’t add context to errors in most cases?Personally I haven’t found the need to add context to errors in Rust anywhere close to 95% of the time. Usually a stacktrace has already been captured and there isn’t much to add.
It seems to vary a lot, and especially older projects (before the
fmt.Errorf()stuff was added) probably don’t attach context.Usually I want to add identifiers (e.g., filepaths, resource identifiers, etc) to errors, so rather than “permission denied”, you get “opening
/foo/baz.txt: permission denied”. I also haven’t found a very satisfying way to attach stack traces to errors–do you check each call site to determine whether it has already attached the stack trace? Maybe that’s reasonable, but what I usually do is make sure each function adds an annotation that says what it’s doing (e.g.,OpenFile()will annotate its errors withfmt.Errorf("opening file%s: %w", path, err)). I definitely don’t think that’s an ideal solution; it’s just the best one I’ve found so far. 🤷♂️[Comment removed by author]
Also probably no exceptions is a natural technical constraint for you already, right
Depends on your requirements; I’d say for a small game, the runtime & binary size cost of exceptions isn’t large enough to matter that much for you.
My hope is this doesn’t go through, it’s merely a syntactic sugar that unfortunately introduces more questions than it answers. The comments bring up a lot of real issues with zero-or-not value, automatic err variable declaration, etc.
I can think of others edge cases too, like functions that return a concrete type that happen to implement the error interface, or returning the error at different positions in the tuple. These questions shouldn’t be ignored, semantic concerns should trump syntax.
The real problem is that error handling is not statically enforced. If that won’t change I see no reason to reduce boilerplate by one line.
I’m usually very critical of error handling proposals, but I really like this one. It keeps the spirit of current error handling instead of trying to replace it.It does look a bit weird on first sight but I easily can imagine getting used to it.I’m not a big fan of the automatic err variable declaration though.
Edit: reading more into it, I don’t like the automatic return when ? is not followed by a block.
This example is too far from current Go idioms, visually (without reading it) I thought it was an interface declaration. I wish they would keep explicit err return like this:
Edit 2: I don’t like it anymore.
I really dislike this. It seems to solve a non-issue in a very un-Go-like way.
This is a very confusing proposal and problem. When I write go, I’m more concerned I have to rely on checked casts just to know if the err I have is what I think it is and I can never guarantee I have an exhaustive set of branches for every possible (possibly even nested and wrapped) error. I don’t see how sugaring over:
really solves the biggest problem I see and I can’t imagine
if err != nilis a struggle for many.This can’t land fast enough.
if err != nilreads simple on its face, but has always felt extremely clunky and error prone, and comes with an air of “well simply don’t forget to check for nil here!” It’s one of many reasons I’ve never enjoyed writing Go and have joked that it’s a world-class ecosystem and toolchain lacking only a decent language.Changing all return signatures of the Go ecosystem would be a fatally breaking change, so at least reducing the boilerplate to make the existing signatures more ergonomic (and maybe a bit less error prone) feels like a huge positive to me.
OK, interesting. I was gonna dismiss this as one of the thousand “let’s put a new syntax on an idea that has been suggested many times” proposals, but this one is by Ian Lance Taylor, a member of the Go Team.
It would be convenient for functions that return (result, err) pairs if
?with no block returned zero for the result and passed through the err.This proposal mentions a separate one to allow writing
return ..., errinstead ofreturn result, err, but I don’t see any examples suggesting that’s going to kick in automatically for?with no block. The case for adding that behavior is just this occurs a lot and this would make it more concise. I imagine the case against has to do with complexity or the potential for mistakes.If the argument is mostly about implementation difficulty, I hope it’d be considered for addition later if it doesn’t make the initial implementation.
I guess this is fine? It doesn’t really do much.
This is the year of
linuxsane error handling inthe desktopgo.Something tells me midlang devs are not going to be very enthusiastic about this syntax and how “complex” it is.
What’s a midlang dev?
My guess: mid is a slang for average and often used pejoratively. so it means average language.
My guess: 4chan slang for golang.
Thank you. Exactly.
I find midlang to perfectly describe the ethos of Go. Everything in it is perfectly so-so, with the language trying really hard to prevent anyone from coming up with anything “too smart” in an name of avoiding all the possible bad uses.
Costed me some dowvotes, but it’s true. :D . And I will be surprised if a community will be happy about a weird, unconventional error handling operator. Though … it is kid of mid too… so maybe?
Am I the only one who tires of language holy war stuff?
My guess: typo for middling.