Components in Scala

Martin Odersky will talk about components in Scala. See also the first four Scala lectures at laser.

Components are parts of applications that can be combined in larger applications. They should be reusable, and therefore it needs an interface,  both describing the provided and the required services. This is how it differs from an API.

A component should refer to others via members of parameters (so not statics) This is surprisingly hard to achieve.

In principle Functors work really well for this, but in practice this is often like this:

This is why we need component abstraction. Two priciple forms are:

  • parameterization (FP)
  • abstract members (OO)
Scala uses abstract members both for composition and encapsulation. Then a component is a trait, and interface is a fully abstract trait, a required component is a abstract member and composition is a mixin. It is also possible to access a class without knowledge of the binding of its type member, this is called path-dependent typing.
So how can we express required services of a component? By abstracting over them!
With the ‘with’ keyword, (mixin composition) we can combine traits with types. Concrete definitions in the one base trait override abstract definitions in the other. A more concise version of this is achieved through self-typing. This means as a trait, you can type yourself (“this”). That feels strange, but works out strangely fine. It looks like this:
trait X {this: Types with Symbols => trait X (def: tpe:Type}

What about contracts in Scala?

Scala does not have contracts, but can they be added after the fact?

First let’s have a look at how other language implement this. Some languages have contracts as part of the language, most notable is of course Eiffel. JML puts them in the comments in a funny syntax. But this is disconnected from the language ans has to do its own parsing and type checking. Now, Java has annotations, but this is not that different from comments. A different way is to put the contract in code. This is a good re-use of language features and parsing and type-checking come for free. However, it is quite verbose.

Scala has contracts as code with four constructs: assert, assume, require, ensuring. Assert and require are implemented with simple predef objects. Ensuring is technically a method call, that is made possible by an implicit conversion. Classes that use an invariant have to extend the invariant trait, which adds its call-by-name parameter as a closure.

This implementation is extremely lightweight, because of the reuse of language features.  Downsides are that some things can’t be expressed, like precondition weakening.

Martin concludes: Scala feels very different for producers (sophisticated toolset with which you can push boundaries of what’s possible) and consumer (easy, intuitive, so user can concentrate on the domain).

Want to learn more about Scala? I enjoyed Scalabound.