Subtype in Scala: what is "type X <: Y"?

scala, subtype, type-constraints

Solution

I know that code! :)

So let's make sure you understand what `<:` means, just in case. `A <: B` means that `A` must be a subtype of `B`, or, to put it in other words, every instance of `A` will be an instance of `B` as well (but not vice versa).

We know, for example, that every java class is `<: Object` (such as `String <: Object`).

Next, why `type ValueChanged <: Event`. This is usually found in the cake pattern, but I'll skip an explanation of that (the lesson did mention the cake pattern, and provided a link iirc).

What that means is that for anything that extends `SwingApi`, the type `ValueChanged` must be a subtype of `Event`. That makes it possible to call `Event` methods on anything that is declared with the type `ValueChanged`, without knowing beforehand exactly what type is that.

That is similar to the next use:

type TextField <: {
    def text: String
    def subscribe(r: Reaction): Unit
    def unsubscribe(r: Reaction): Unit
}

We are declaring here that `TextField` should have those methods, so when we get something of the type `TextField` (such as returned by the `ValueChanged` extractor), we can call these methods on it. We could write code like this:

trait MyStuff extends SwingApi {
  def subscribeTo(event: ValueChanged) = event match {
    case ValueChanged(textField) => textField.subscribe(myReaction)
  }

  def myReaction: Reaction
}

At this point, neither `SwingApi` nor `MyStuff` know what types are going to be used for `ValueChanged` or `TextField`, and, yet, they can use them in normal code.

One interesting fact that is often overlooked about `type` declarations is that they can be overridden by classes. That is, I can write something like this:

class SwingImpl extends SwingApi {
  class TextField {
    def text: String = ???
    def subscribe(r: Reaction): Unit = ???
    def unsubscribe(r: Reaction): Unit = ???
  }

  // etc
}

Finally, you might wonder what use is this. I'll give one example. Naturally, you want the production code to show graphical elements on the screen and such, and, perhaps, you could write a separate class that implements it in a web server. But, and I think course takes advantage of it, you could write the class that implements it not as something that displays these components, but as test classes, that verify that the interaction with these components is being done correctly.

That is, you can have a `SwingImpl` that extends `SwingApi` and show the stuff on your desktop, and a `SwingTest` that also extends `SwingApi`, but simply let people verify what is being done.

Problem

Can anyone explain the subtype(<:) in the following code? Why it could be used like that? When we use that? Thanks. ``` trait SwingApi { type ValueChanged <: Event val ValueChanged: { def unapply(x: Event): Option[TextField] } type ButtonClicked <: Event val ButtonClicked: { def unapply(x: Event): Option[Button] } type TextField <: { def text: String def subscribe(r: Reaction): Unit def unsubscribe(r: Reaction): Unit } type Button <: { def subscribe(r: Reaction): Unit def unsubscribe(r: Reaction): Unit } } ```

Original source