For better syntax and user friendliness (and a lot more), Java 8 introduces SAM type, Single Abstract Method type, starting to embrace the functional programming world.
Previous to 1.8, Java already has somewhat a (bulky and leaky) type of closure: annonyous inner classes. For example, to start a working thread in Java usually requires following trivial but bloated statements, without a lexical this
:
1 | // from android developer guide |
Two classes, one method. The introduction of SAM type greatly reduces the syntactical overhead of Java.
1 |
|
I’m not explaining Java8’s new features here, as a Scala user has already relished the conciseness and expressiveness of functional programming.
So, why would scala user cares about SAM type in Java? I would say that interoperation with Java and performance are the main concerns here.
Java8 introduces Function
type, which is widely used in library like stream
. Sadly, Function
is not that of scala. Scala compiler just frowns at you using scala native function with Stream.
1 | import java.util.Arrays |
Side notes: because function parameter is in a contravariant position, Function[_ >: Int, _]
has a lower bound Int rather than a upper bound.
That is, the function passed as argument must accept types that are super types of Int
.
One can manually provide implicit conversion here to transform scala function types to java function types. However, implementing such implicit conversion is of no fun. The implementation is either not generic enough, or requires mechanical code duplication(another alternative is advanced macro generation). Compiler support is more ideal, not only because it generates more efficient byte code, but also because this precludes incompatibility across different implementations.
SAM type is enabled by -Xexperimental
flag in scala 2.11.x flags. Specifically, in scala 2.11.5, SAM type is better supported.
SAM gets eta-expansion(one can use a method from another class as SAM), overloading(overloaded function/method can also accept functions as SAM) and existential type support in scala 2.11.5.
Basic usage os SAM is quite simple, if a trait/abstract class
with exactly one abstract method
, then a Function
of the same parameter and return type of the abstract method can be converted into the trait/abstract class
.
1 | trait Flyable { |
Easy Peasy. So for the stream
example, if compiler has the -Xexperimental
flag, scala will automatically change the function to java’s function, which grant scala user a seamless experience with the library.
Usually, you don’t need SAM in scala, as scala already has first class generic function type, eta-expansion and a lot more. SAM reduces the readability as implicit conversion does. One can always use type alias to give function a more understandable name, instead of using SAM. SAM type cannot be pattern matched, at least for now.
However, interoperating with Java requires SAM. And self-referencing SAM gives you additional flexibity in designing API. SAM also generates more efficient byte code since SAM has a native byte code counterpart. Using annonymous class for event handler or callback can be more pleasant in Scala just as in Java.
Anyway, adding a feature is easy, but adding a feature that couples with edge case is hard. Scala already has bunches of features(variance, higher kinded, type level, continuation), whether SAM will gain its popularity is still an open question.