Because Option
s are composable. There are a lot of useful methods on Option
that allow you to write concise code, while still allowing precise control on the flow: map
, flatMap
, toList
, flatten
and more. This is due to the fact that Option
is a particular kind of monad, some objects that we know very well how to compose. If you did not have these methods and had to pattern match always on Option
, or call isDefined
often, they would not be nearly as useful.
Instead, while checked exceptions do add some safety, there is not much you can do with them other than catching them or let them bubble up the stack (with the added boilerplate in the type declaration).
Break and Continue:
In a talk about Scala, Martin Odersky gave 3 reasons not to include break or continue on slide 22:
- They are a bit imperative; better use many smaller functions.
- Issues how to interact with closures.
- They are not needed!
And he then says, "We can support them purely in the libraries." On slide 23, he gives code that implements break
. Although I don't quite know Scala well enough to be certain, it looks like the short snippet on that slide is all that's needed to implement break
, and that continue
could be implemented in code that is similarly short.
Being able to implement stuff like this in libraries simplifies the core language.
In 'Programming in Scala, Second Edition', by Martin Odersky, Lex Spoon, and Bill Venners, the following explanation is given:
You may have noticed that there has been no mention of break
or continue
. Scala leaves out these commands because they do not mesh well with function literals... It is clear what continue
means inside a while
loop, but what would it mean inside a function literal? ... There are many ways to program without break
and continue
, and if you take advantage of function literals, those alternatives can often be shorter than the original code.
Return:
Returns could be considered a bit imperative in style, since return is a verb, a command to do something. But they can also be seen in a purely functional/declarative way: they define what the return value of the function is (even if, in a function with multiple returns, they only each give a partial definition).
In the same book, they say the following about return
:
In the absence of any explicit return
statement, a Scala method returns the last value computed by the method. The recommended style for methods is in fact to avoid having explicit, and especially multiple, return
statements. Instead, think of each method as an expression that yields one value, which is returned.
Methods end and return a value, even if a return
statement isn't used, so there can be no issues with closures, since otherwise closures wouldn't work period.
There can also be no problem meshing well with function literals, since the function has to return a value anyway.
Best Answer
Exactly. They can be seen that way, and they should be but they aren't.
Using an
Error
type like is common in Rust, Elm, Haskell, and in some sub-communities in Scala or a special error value as in Go is just an alternative return value indicated in the type system. A checked exception is like an alternative return value, but it doesn't use the normal way of returning values, it is a completely separate, very different way of "returning values". It also sits outside of the type system, and bolts on a completely separate "checked exception" system onto the type system.But most importantly, it is not just an alternative return value, it is also an alternative control flow.
Another problem with the specific way checked exceptions are implemented in Java, is that they are anti-modular. That is, however, not a fundamental problem of checked exceptions, unlike the ones I mentioned above. There is an idea of Modular Anchored Exceptions, for example, where you can specify something like
And you don't have to know (and leak!) which precise exceptions
bar
can throw. You can even do something likethrows like bar except ArrayOutOfBoundsException
when you are handling some errors yourself.