That's completely incorrect: it's trivial (and common) to just ignore errors in Go:
ok, _ := Foo()
Checked exceptions don't let you get away with this kind of sloppy programming.That's completely incorrect: it's trivial (and common) to just ignore errors in Go:
ok, _ := Foo()
Checked exceptions don't let you get away with this kind of sloppy programming. try {
ok = foo()
} catch (Exception e) {
// Do nothing
}
Checked exceptions don't save you from "this kind of sloppy programming".As an aside, I once tried using a crypto library to do something fairly simple (encrypt a file I'm writing to disk), and I had to handle a whole stack of exceptions that I had no clue how to handle. So what can you do? You should be able to write code that provides sensible default behavior, but checked exceptions make you work to just get that behavior, which is not how default behavior is supposed to work.
Return value errors like Go implements forces everyone to care about all errors, at all times, even those they can't handle, which is why you see the pattern
ok, err:= Foo()
if err {
every ten lines in Go sources.If those were runtime exceptions, my program would just crash on error, which is the default I wanted. I didn't want to pollute my code with error handling stuff just to try out some simple functionality. If they were runtime exceptions, I could learn to use the code from the ground up, not by having to understand the whole thing at once.
That's exactly the point: not everyone along the method stack is forced to deal with it, only the one caller that knows how to handle it.
> The problem is that I don't know where it should be handled
Then don't handle it at all and let it crash the program. But at least you didn't add boiler plate simply bubbling up an Err at every level of the stack frames.
> If those were runtime exceptions, my program would just crash on error, which is the default I wanted
Sometimes it is, sometimes it isn't. Some exceptions should crash your program (runtime exceptions), others should be handled (checked exceptions). Languages that take correctness seriously should offer you both options.
My goal wasn't to write correct code, it was to test something out. To get comfortable with the library and the task. Checked exceptions get in the way of that.
>Languages that take correctness seriously should offer you both options.
Rust and Haskell take correctness seriously and offer neither. Checked exceptions make perfect sense in terms of ensuring correctness, but they are awful for usability and they are not the only way to achieve correctness.
>Some exceptions should crash your program (runtime exceptions), others should be handled (checked exceptions).
Shouldn't the user determine that, not the implementor? Why should any exceptions not be checked?
Because there are exceptions you can't do anything about (e.g. OutOfMemoryException) and exceptions that you don't know what to do with (e.g. an NPE where you didn't expect it).
NPE is the poster child for an unchecked exception: if you know your code is throwing an NPE here, just fix it instead of catching the NPE.
Now if you choose to handle this stupidly, that's entirely your fault, but at least the compiler did its jobs by forcing you to think about the error case.
In Go, the compiler doesn't enforce anything.
In Go, as in Java with checked exceptions, the compiler forces the programmer to handle the error.
Using _ in Go is not idiomatic. It's the exact equivalent of using a try/catch block with nothing in the catch block in Java.
They sure do. Just write your Java code without a try/catch block anywhere, or just have your catch do absolutely nothing. You can do it, trust me. Exceptions don't stop programmers from doing anything.
The point of checked exceptions is that you can’t do that. It is a compile-time error to not either catch the exception or explicitly indicate that you will propagate it.
Unfortunately, at least in Java, that style proved too onerous for a lot of programmers and motivated the catch-all, do-nothing wrapper idiom that is completely unhelpful as far as safety goes.
Exceptions don't stop programmers from doing anything.
At least in principle, you can statically detect any failures to handle possible exceptions if you have a suitable type system. Of course, if you just hack around those warnings, as we’ve seen Java programmers do with checked exceptions and catch-alls, then you’re no better off than if you ignored a relevant return code in the first place (aside, perhaps, from making it much more obvious to a static analyser or during a code review that you are doing so).
> The point of checked exceptions is that you can’t do that.
Sure you can. You just have to write "throws Exception" after all your function signatures.
You can't. I don't think you understand how checked exceptions work.
try {
foo();
} catch (Exception e) {
;
}
?Also, you don't need the semicolon.
1. Signal to the calling programmer that some error condition can occur. For example having to catch SomethingNotFound tells them that it's possible that Something might not be found.
2. You just put in your coding standards that you must do something sensible inside of a catch block, and get a code checker to break the build.
I don't think anybody is trying to say that checked exceptions have "solved" the problem of people ignoring error conditions. It does at least give you an easily visible thing to point at and say "that's wrong" though.
By that standard, exceptions actually fit in between C-style obliviousness and explicit error returns. They do allow a certain amount of implicitness (does this code have no try/catch exception handlers because the programmer is deliberately invoking the default exception behavior, or is it because they didn't think about errors at all?), but you still can't ignore errors the way you can in C. And then with explicit error returns, you can't ignore them at all without leaving a trail of your decision to do so right there in the source code.
Checked exceptions tried to straddle the boundary, but I think I have to agree with the general consensus that they are a failed experiment. One of my "cut through the noise" metrics for language design decisions is "do any subsequent languages pick up the feature?". If a language as dominant as Java has a feature, but after 10-15 years no new languages are picking up the feature, that Means Something.
do {
try error-return-statement
statement
statement
try error-return-statement
} catch ErrorType1 {
...
} catch ErrorType2 {
...
}
It looks like exceptions, but under the hood error objects are being returned by error-return-statements, thus the explicit try keywords before them. It retains go error object simplicity, but keeps things readable and tidy. err := f1()
if err != nil {..} // have to do this or compiler error
err = f2()
// oops, forgot to actually do anything about it!
Now, granted, `go vet` helps with this, but.. these kinds of things can be solved by the language proper in much better ways, and they should be type errors. Like rust's `Result` or Haskell's `Either`.Edit: rust's result is especially nice with #[must_use]. This has saved my team from mistakes relatively frequently.
var foo *bar
foo.Baz()
Accidentally dereferencing a null pointer in Go is dangerously easyhttps://play.golang.org/p/cjmflMBhF7
Why not learn the language before criticizing it?
if b == nil {
fmt.Println(":)")
} else {
fmt.Println(b.emote)
}
In this case, that's useless, but that's an artifact of the chosen example. I use it every so often in places where it happens to have meaning.Go often treats nil as a legal value, which means that some of the things you might expect to crash don't, and when used idiomatically can sometimes make for shorter code. For instance, the "length" call on slices will happily take a nil and return 0, you can "append" to a nil slice and get a slice back, etc. Ultimately it's still a language with a null in it, though. There's no non-nil pointer type.