why Scala does not have concept of checked and unchecked exception?

TL;DR jump to last paragraph :)

While I completely agree with Tiago's answer, there are a few things that can be added. As you know, Scala is a functional and object-oriented language. The functional aspect of it dictates that side-effects should be eliminated, or at least minimized as much as possible.

Throwing an exception is a side-effect since it is not referentially transparent (ie, it depends on the context of where the exception is thrown, for example if the exception is thrown from inside a try block, it will be caught whereas if it is thrown outside of that try block, it will alter the flow of the program).

Here is an example taken from the book Functional Programming in Scala (P. Chiusano, R. Bjarnason)

 def failingFn(i: Int): Int = {
       val y: Int = throw new Exception("fail!")
       try {
         val x = 42 + 5
         x + y
       }
       catch { case e: Exception => 43 }
 }

In the above code, y is not referentially transparent since if you replace it by its value within the try block, the result of the function will be different.

Ok, enough with all the theory, the key takeaway from the above is that throwing an exception is a side-effect and this violates the functional programming paradigm.
To address this, the designers of Scala decided to instead return "a value" that indicates that an exception occurred, instead of throwing one. For that reason, classes like Try (and its direct subtypes Success and Failure) were introduced. Instead of throwing an exception, you simply modify the return type of your function, wrapping it in a Try. This forces the client to check for success or failure without all the side-effects that throwing exceptions bring. The introduction of the Try type basically replaces checked exceptions since the client is implicitly made aware of the possibility of an exception at compile-time through the use of a Try return type.


Starting Scala 3.1.0-RC1 exception checking can be enabled by

import language.experimental.saferExceptions

For example

scala> import language.experimental.saferExceptions

scala> def foo(): Int = throw new Exception()
-- Error:
1 |def foo(): Int = throw new Exception()
  |                 ^^^^^^^^^^^^^^^^^^^^^
  |        The capability to throw exception Exception is missing.
  |        The capability can be provided by one of the following:
  |         - A using clause `(using CanThrow[Exception])`
  |         - A `throws` clause in a result type such as `X throws Exception`
  |         - an enclosing `try` that catches Exception
  |
  |        The following import might fix the problem:
  |
  |          import unsafeExceptions.canThrowAny
  |

scala> def foo(): Int throws Exception = throw new Exception()
def foo(): Int $throws Exception

The mechanism that enables the compiler to track these exceptions is called capabilities and is implemented by context functions. Note that error capabilities are different from error effect tracking via error monads (such as Either, Option, Try, etc.)

capabilities can be expressed as parameters whereas traditionally effects are expressed as some addition to result values.

This means there is no need to modify the return types in order to track the error, for example consider the difference between

scala> def foo(): Try[Int] = Success(42)       // we have to wrap 42
def foo(): util.Try[Int]

scala> def foo(): Int throws Exception = 42    // just pure 42
def foo(): Int $throws Exception

As to possible reason why Scala did not implement Java's checked exception mechanism same document explains

The main problem with Java's checked exception model is its inflexibility, which is due to lack of polymorphism.


I don't know the exact reason why Scala chose not to have checked exception, but one can say that's the common approach. How many other languages do you know that have checked exceptions besides java?

I will point out something I saw in a lot of java programs over the years, and I'm sure if you did serious java programming you have seen it too:

try {
  // do stuff
} catch (Exception e) {
  throw new RuntimeException(e);
}

try {
  // do stuff
} catch (Exception e) {
  // do nothing
}

Sure you can say that's lazy programming, and the latter truly is. But it shows you a problem. You sometimes can't and don't want to handle the exception in place, you want the program to break, or the exception to bubble up to a higher-level component that will handle the errors.

And you may be thinking right now You just need to add throws in the method signature but more often than not you can't. And I can give you a clear example of this problem using java 8 lambdas.

list.stream().map(item -> {
  // throws a checked exception. compilation error
  return normalizeItem(item);
});

In the code above, you will need to handle the exception, using one of the two techniques shown above. You can of course create a new functional interface that throws an exception, but you will need to recreate all the standard ones just to annotate them with throws. If you ask me, this is a real mess.

I think that's one of the reasons. Scala is functional from the beginning and checked exceptions don't go well with this, as you can see.

You can read a much more thorough discussion here