65

I'm looking at p. 469 of "Programming in Scala" Second Edition. There is a line of code that reads:

type Currency <: AbstractCurrency

I cannot decipher what this means.

nbro
  • 15,395
  • 32
  • 113
  • 196
deltanovember
  • 42,611
  • 64
  • 162
  • 244
  • 6
    See also [What does “trait A <: B” mean?](http://stackoverflow.com/questions/2123663/what-does-trait-a-b-mean) – Jonas Jul 26 '11 at 11:10

4 Answers4

70

It means an abstract type member is defined (inside some context, e.g. a trait or class), so that concrete implementations of that context must define that type. However, there is a constraint that this type (Currency) must actually be a subtype of AbstractCurrency. That way the abstract context can operate with Currency, knowing that it understands every operation of AbstractCurrency.

trait AbstractCurrency {
  def disappearInGreece(): Unit
}

abstract class Economy {
  type Currency <: AbstractCurrency

  def curr: Currency

  // can call disappear... because `Currency`
  // is an `AbstractCurrency`
  def shake(): Unit = curr.disappearInGreece()
}

Trying to define Currency without constraints:

trait RadioactiveBeef

class NiceTry(val curr: RadioactiveBeef) extends Economy {
  type Currency = RadioactiveBeef
}

Fails. With constraints ok:

trait Euro extends AbstractCurrency

class Angela(val curr: Euro) extends Economy {
  type Currency = Euro
}
0__
  • 66,707
  • 21
  • 171
  • 266
47

It means "must be a subtype of", "must conforms to", "must extends". Most of the time, it would appear as a bound on a generic parameter, such as

class Home[P <: Person] 

Each Home is fit for a certain type of person, a Home[Person] accepts any person, there might be Home[Student], Home[Elderly], but no Home[Planet].

type Currency <: AbstractCurrency introduces an abstract type member Currency in the class/trait where it appears. Descendants will have to choose a type so that they can be concrete. The <: AbstractCurrencies force them to choose a subtype of AbstractCurrency (including AbstractCurrency, which is allowed).

An abstract type member is very close to a type parameter, just as an abstract value member is close to a constructor parameter.

If you have class A(val x: X){...}, you instanciate the first with new A(myX). If you have class A{val x: X; ...}, you instanciate with new A{val x = myX }.

If you have class Market[Currency <: AbstractCurrency] you instanciate the type with Market[SomeCurrencyType]. If you have Market{type Currency <: AbstractCurrency}, you instantiate with Market{type Currency = SomeCurrencyType}. However, Market is a valid type. It means you don't know what type of currency this market uses (which may restrict how you can use it).

Using an abstract type member rather than a type parameter may have benefits, mostly if the type parameter does not appear in the public interface of the type, if Market has no Currency appearing as a function parameter or result (not too likely on this example). Then client does not need to write Market[SomeCurrencyType], Market will do. Of course, the CurrencyType will have to be known when a market is created, but then it may be passed along simply as Market.

nbro
  • 15,395
  • 32
  • 113
  • 196
Didier Dupont
  • 29,398
  • 7
  • 71
  • 90
15

I want to add some points which will describe the usability benefits of the <: notation.

Let us say, you define the following class for your API:

case class myApiClass[param <: BaseParameter](requestBody: String, parameter: param)

You have a trait called BaseParameter

trait BaseParameter

Then, you have the following parameters:

case object Parameter1 extends BaseParameter
case object Parameter2 extends BaseParameter
case object Parameter3

Now, whenever you create a myApiClass instance, you must pass an object as the argument "parameter", whose class/which itself implements BaseParameter (e.g. Parameter1 and Parameter2). Concretely, this is an assertion, and would not work if you pass Parameter3.

Arijit
  • 420
  • 7
  • 14
8

This question is about Scala but I think it's worth mentioning that the <: [type operator?] is not unique to Scala and instead originates in Type Theory; see for example the article about Subtyping on Wikipedia which makes extensive use of this operator.

In fact, due to its strong connections with type theory <: is not the only thing Scala (elegantly) borrowed from it; for example the term: Type notation (seen in e.g. val foo: Foo, def fact(x: Int): Int) also comes from Type Theory.

Erik Kaplun
  • 37,128
  • 15
  • 99
  • 111