Scala generics in an abstract function - scala

There is an abstract class Animal.
Animal is extended by Dog and Cow.
Animal has an abstract function copy. When called on Dog is should return Dog and when called on Cow - Cow.
abstract class Animal[T] {
def copy[CT <: Animal[T]] (): CT
}
class Dog[T] extends Animal[T] {
def copy = new Dog[T]()
}
This gives an error. What am I doing wrong?

Your copy method in Dog does not have the same signature as the copy method in Animal (Animal has a type parameter and Dog does not), so the Scala compiler thinks you haven't implemented it for Dog. It looks like you're trying to work around the fact that copy should return the sub-type. You can use a self-type for this:
abstract class Animal[T] { self: T =>
def copy: T = this
}
class Dog extends Animal[Dog]
Unless you had something else in mind for the type parameter?
It might also be more prudent to use F-bounded polymorphism in this case, to verify that T is a sub-type of Animal.
abstract class Animal[T <: Animal[T]]

Essentially CT must be invariant for your approach to work. Your concrete implementation of Dog has no control over the type of CT, for example it's impossible to account for this with your approach (hence the compiler error):
new Dog[Int]().copy[Cow[Int]]()
Your concrete implementation gives me a Dog but I wanted a Cow. This is because your copy method cannot possibly satisfy the return type parameter variance. If all you need is one return type for the copy method you could employ this alternative (inspired by the same problem as it occurs in C++):
abstract class Animal[T, SubType <: Animal[T, _]] {
def copy (): SubType
}
class Dog[T] extends Animal[T, Dog[T]] {
override def copy() = new Dog[T]
}
val animal: Animal[Int, Dog[Int]] = new Dog()
val dogCopy: Dog[Int] = animal.copy()
Here's another simpler (not as obvious) approach. Scala permits you to override not just the implementation of a method, but also the return type to some degree:
abstract class Animal[T] {
def copy (): Animal[T]
}
class Dog[T] extends Animal[T] {
override def copy() = new Dog[T]
}
val dog = new Dog[Int]()
val dogCopy: Dog[Int] = dog.copy()

Related

In Scala how do I define upper type bounds that are exclusive of the defined class?

Given a concrete class Animal, how do I define a function that only takes a subclass of Animal?
In typical examples like this Animal is a trait so defining [A <: Animal] implies that you already pass in a subclass of Animal. However, in a scenario like below where Animal is concrete, can I exclude that as being an allowed type?
I'm working with existing generated code, and this is just a generalized example of the problem. Therefore the implication is that I can't make Animal (or the equivalent) into a trait.
See below for an example:
class Animal {
def name: String = "General Animal"
}
class Dog extends Animal {
override def name: String = "Dog"
}
// How do I limit A to be a subtype of Animal (excluding Animal itself)?
class SpecificAnimalContainer[A <: Animal](a: A) {
def specificAnimal: A = a
}
val dogContainer = new SpecificAnimalContainer[Dog](new Dog)
// I do not want this to be able to compile.
val animalContainer = new SpecificAnimalContainer[Animal](new Animal)
Using shapeless you can write:
import shapeless._
class SpecificAnimalContainer[A <: Animal](a: A)(implicit ev: A =:!= Animal) {
def specificAnimal: A = a
}
// val animalContainer = new SpecificAnimalContainer[Animal](new Animal)// doesn't compile
Otherwise you can implement similar type for implicit yourself.
Type constraint for type inequality in scala
Enforce type difference
How can I have a negation type in Scala?
It's a bit unclear what you're trying to achieve, but your problem looks exactly like a book example from Scala documentation at
https://docs.scala-lang.org/tour/upper-type-bounds.html
abstract class Pet extends Animal {}
class PetContainer[P <: Pet](p: P) {
def pet: P = p
}
class Lion extends Animal {
override def name: String = "Lion"
}
// val lionContainer = new PetContainer[Lion](new Lion)
// ^this would not compile
Hope this helps

Return class instance using generic inside companion object for method specified in trait

In Scala I want to return a instance of a class for a method defined in a trait which uses generics, the code example I have is this:
File 1
package packOne
import packTwo.A
trait MyTrait[T <: MyTrait[T <: A]] {
def otherFunct(): String
def funct[T <: A](): T
}
File 2
package packTwo
import packOne.MyTrait
abstract class A(someParameter: String) {}
class B(someParameter: String) extends A(someParameter) {}
object B extends MyTrait[B] { // <--- the B inside MyTrait here is the class not the object, or at least that is what I want
def otherFunct(): String = "Hello"
def funct[B](): C = new B("hi") // <--- I think here is the key
}
basically what I want is an interface that have method to return a concrete implementation of class A, in an implementing object (which happen to be a companion object for a class extending A).
Why do I want that to be on an object?, is because I want to call that method without the need of an instance (like an static method in java), so that I can call B.funct() and have an instance of B class kind of like a factory method, for other classes extending A for example a call to X.funct will return an instance of class X.
I have tried to remove the generic type from the function definition except on the return type of the function and just leave it in the trait definition (like def funct(): T) but that does not work either.
I am quite new to Scala so if you could explain it for dummies and avoid complex scala unique concepts I would appreciate
How about simply:
trait A
class B(someParameter: String) extends A
trait MyTrait[T <: A] {
def otherFunct: String //Parentheses on parameterless methods with no side effects and no serious computation are generally unidiomatic in Scala
def funct: T //Note, no generic parameter on this method
}
object B extends MyTrait[B] {
def otherFunct = "Hello"
def funct = new B("hi")
}
And then:
B.funct //returns a new `B`
The apply method is often used in this factory style (e.g. Seq.apply() which is equivalent to Seq())

Scala - Abstract types and Implicit Parameter Resolution

I'm using Scala 2.10.4.
Please bare with the analogy - the actual code is deeply embedded in a complicated program, so rather than explain that, I’ll abstract the problem in a time honoured way to talk about Animals ;-)
In scala I have 2 traits - for example:
Animal, and HouseBase.
I have no access to change Animal, but I inherit from it with classes like Dog, Rabbit, Fish. Annoyingly I can’t change every subclass as I don’t own all the subclasses I use.
My animals all live somewhere - their homes must inherit from HouseBase. I can change HouseBase and it’s subclasses (via another layer of abstraction, if I must).
So a Dog is a subclass of Animal, and would live in a Kennel which is a subclass of HouseBase.
A Rabbit would live in a Hutch, and a Fish in a Tank.
Note there is not a 1:1 relationship enforced here - a Fish could also live in a Pond, and we’d have to be able to handle that too.
What I’d hoped was that -- given a concrete animal (eg Fish), that is referenced via an abstract type Animal, and given a concrete return type (eg Tank), Scala would be able to automagically pick the correct implicit parameter in the design I have below.
object AnimalSelectionProblem extends App {
def abstractFish : Animal = new Fish(true, 20.0)
def concreteFish : Fish = new Fish(false, 30.0)
def abstractDog : Animal = new Dog("tasty bone")
def concreteDog : Dog = new Dog("yummy bone")
def abstractRabbit : Animal = new Rabbit(5)
def concreteRabbit : Rabbit = new Rabbit(10)
import HouseImplicits._
val myTank1: Tank = HouseImplicits.create(abstractFish)
val myTank2: Tank = HouseImplicits.create(concreteFish)
val myKennel1: Kennel = HouseImplicits.create(abstractDog)
val myKennel2: Kennel = HouseImplicits.create(concreteDog) // This works
val myhutch1: Hutch = HouseImplicits.create(abstractRabbit)
val myhutch2: Hutch = HouseImplicits.create(concreteRabbit) // This works
}
However there are 2 related problems.
Problem 1 - If the animal is referenced as an abstract, then the implicit parameter will only look for functions that take the abstract type (Animal) rather than the underlying concrete type. I suspect the solution may be to use ClassTags, because Scala doesn’t seem to use runtime time information? I had a go at implementing this and got hopelessly l lost (I’m fairly new to Scala!).
Problem 2 - If my animal can live in more than one type of House then a similar issue occurs, that even if a concrete return type is specified, the compiler will find the 2 implicit objects for Fish ambiguous. I’m a bit stumped about what to do here!
I can dream up solutions with manual boilerplate to match the type at runtime, but this isn’t very extensible.
Any ideas gratefully received! Rest of the code is below.
Edit - these links seems to confirm what I had suspected. That compile time polymorphism is used and hence the runtime type cannot be known:
http://like-a-boss.net/2013/03/29/polymorphism-and-typeclasses-in-scala.html
https://softwareengineering.stackexchange.com/questions/258698/is-it-possible-to-have-ad-hoc-polymorphism-with-runtime-dispatch
So, I guess my question now is, given this, is there a way to modify my example to use runtime dispatch?
Animals:
trait Animal {
}
class Dog(val boneName: String) extends Animal
class Rabbit(val length: Int) extends Animal
class Fish(val likesFrogs: Boolean, val optimumTemp: Double) extends Animal
Houses and Implicits:
sealed trait HouseBase
// Made up some arbitrary member variables
case class Kennel(posessions: Seq[String]) extends HouseBase
case class Hutch(length: Int) extends HouseBase
case class Tank(waterTemp: Double) extends HouseBase
case class Pond(containsFrog: Boolean) extends HouseBase
sealed trait HouseCreator[A <: Animal, HB <: HouseBase] {
def create(animal: A): HB
}
object HouseImplicits {
implicit object BuildKennelForDog extends HouseCreator[Dog, Kennel] {
override def create(dog: Dog): Kennel = {
new Kennel(Seq(dog.boneName))
}
}
implicit object BuildTankForFish extends HouseCreator[Fish, Tank] {
override def create(fish: Fish): Tank = {
new Tank(fish.optimumTemp)
}
}
implicit object BuildPondForFish extends HouseCreator[Fish, Pond] {
override def create(fish: Fish): Pond = {
new Pond(fish.likesFrogs)
}
}
implicit object BuildHutchForRabbit extends HouseCreator[Rabbit, Hutch] {
override def create(rabbit: Rabbit): Hutch = {
new Hutch(rabbit.length*5)
}
}
def create[A <: Animal, H <: HouseBase](animal: A)(implicit house: HouseCreator[A,H]) : H = {
val newHouse = house.create(animal)
newHouse
}
}
So basically you want the following design:
At compile time the concrete type of HouseBase is known.
At compile time the concrete type of Animal is not known.
Create a specific type HouseBase for Animal provided runtime animal data.
Can't change Animal implementations, and don't really want to change HouseBase implementations.
The desirable thing is of course to have the concrete types of Animals available at compile time. Since there seems to be some knowledge of that (you know which HouseBase to create for an animal variable at compile time), you may try to use type-safe cast from shapeless to get an Option of a concrete Animal type.
But if it's not possible you have to use run-time dispatch of animals.
In that case I think the method create should have the following signature:
def create[HB <: HouseBase](animal: Animal): Option[HB]
You know the concrete type of the HouseBase so you may as well pass it as type parameter, and the return value is Option to account for a possible mismatch between the type of the provided animal and suitable animal types for a concrete HouseBase
One possible way to implement that is the following code with a single object that has all the knowledge about the production of HouseBases from Animals (it should be also possible to achieve the same thing by moving the creation code into companion objects of concrete HouseBases):
sealed trait HouseCreator[HB <: HouseBase] {
def create(animal: Animal): Option[HB]
}
object HouseCreator {
implicit object KennelCreator extends HouseCreator[Kennel] {
def create(animal: Animal): Option[Kennel] = animal match {
case dog: Dog => Some(Kennel(Seq(dog.boneName)))
case _ => None
}
}
implicit object HutchCreator extends HouseCreator[Hutch] {
def create(animal: Animal): Option[Hutch] = animal match {
case rabbit: Rabbit => Some(Hutch(rabbit.length * 5))
case _ => None
}
}
implicit object TankCreator extends HouseCreator[Tank] {
def create(animal: Animal): Option[Tank] = animal match {
case fish: Fish => Some(Tank(fish.optimumTemp))
case _ => None
}
}
implicit object PondCreator extends HouseCreator[Pond] {
def create(animal: Animal): Option[Pond] = animal match {
case fish: Fish => Some(Pond(fish.likesFrogs))
case _ => None
}
}
def create[HB <: HouseBase : HouseCreator](animal: Animal): Option[HB] =
implicitly[HouseCreator[HB]].create(animal)
}
Then you can call the functions this way:
val myTank1: Option[Tank] = HouseCreator.create[Tank](abstractFish)
val myTank2: Option[Tank] = HouseCreator.create[Tank](concreteFish)
// Types of the variables can also be inferred automatically
val myKennel1 = HouseCreator.create[Kennel](abstractDog)
val myKennel2 = HouseCreator.create[Kennel](concreteDog)
val myhutch1 = HouseCreator.create[Hutch](abstractRabbit)
val myhutch2 = HouseCreator.create[Hutch](concreteRabbit)
Also, the boilerplate code in HouseCreator can be reduced by using PartialFunctions:
sealed trait HouseCreator[HB <: HouseBase] {
def create: PartialFunction[Animal, HB]
}
object HouseCreator {
implicit object KennelCreator extends HouseCreator[Kennel] {
def create = {
case dog: Dog => Kennel(Seq(dog.boneName))
}
}
implicit object HutchCreator extends HouseCreator[Hutch] {
def create = {
case rabbit: Rabbit => Hutch(rabbit.length * 5)
}
}
implicit object TankCreator extends HouseCreator[Tank] {
def create = {
case fish: Fish => Tank(fish.optimumTemp)
}
}
implicit object PondCreator extends HouseCreator[Pond] {
def create = {
case fish: Fish => Pond(fish.likesFrogs)
}
}
def create[HB <: HouseBase : HouseCreator](animal: Animal): Option[HB] =
implicitly[HouseCreator[HB]].create.lift(animal)
}
What you want is for the compiler to deduce the run-time type of your subclass when it is declared statically as an instance of its superclass. This is provably impossible, so don't try to make it work unless you're hoping to win some kind of computer science award!
Instead of parameterizing your HouseCreator class, you could write it to have a single create() method that accepts an object of type Animal. It could create the appropriate House using a case match that matches based on the run-time subtype of Animal.
sealed trait HouseCreator {
def create(animal: Animal): HouseBase {
animal match {
case dog: Dog => new Kennel(Seq(dog.boneName))
case fish: Fish => // etc...
}
}
}
This would only be able to return a HouseBase object rather than a specific subclass (at least as I implemented it here). You could always case match the return value as well.

Understanding use of "this: SomeClassOrTrait =>" in Scala [duplicate]

A self-type for a trait A:
trait B
trait A { this: B => }
says that "A cannot be mixed into a concrete class that does not also extend B".
On the other hand, the following:
trait B
trait A extends B
says that "any (concrete or abstract) class mixing in A will also be mixing in B".
Don't these two statements mean the same thing? The self-type seems to serve only to create the possibility of a simple compile-time error.
What am I missing?
It is predominately used for Dependency Injection, such as in the Cake Pattern. There exists a great article covering many different forms of dependency injection in Scala, including the Cake Pattern. If you Google "Cake Pattern and Scala", you'll get many links, including presentations and videos. For now, here is a link to another question.
Now, as to what is the difference between a self type and extending a trait, that is simple. If you say B extends A, then B is an A. When you use self-types, B requires an A. There are two specific requirements that are created with self-types:
If B is extended, then you're required to mix-in an A.
When a concrete class finally extends/mixes-in these traits, some class/trait must implement A.
Consider the following examples:
scala> trait User { def name: String }
defined trait User
scala> trait Tweeter {
| user: User =>
| def tweet(msg: String) = println(s"$name: $msg")
| }
defined trait Tweeter
scala> trait Wrong extends Tweeter {
| def noCanDo = name
| }
<console>:9: error: illegal inheritance;
self-type Wrong does not conform to Tweeter's selftype Tweeter with User
trait Wrong extends Tweeter {
^
<console>:10: error: not found: value name
def noCanDo = name
^
If Tweeter was a subclass of User, there would be no error. In the code above, we required a User whenever Tweeter is used, however a User wasn't provided to Wrong, so we got an error. Now, with the code above still in scope, consider:
scala> trait DummyUser extends User {
| override def name: String = "foo"
| }
defined trait DummyUser
scala> trait Right extends Tweeter with User {
| val canDo = name
| }
defined trait Right
scala> trait RightAgain extends Tweeter with DummyUser {
| val canDo = name
| }
defined trait RightAgain
With Right, the requirement to mix-in a User is satisfied. However, the second requirement mentioned above is not satisfied: the burden of implementing User still remains for classes/traits which extend Right.
With RightAgain both requirements are satisfied. A User and an implementation of User are provided.
For more practical use cases, please see the links at the start of this answer! But, hopefully now you get it.
Self types allow you to define cyclical dependencies. For example, you can achieve this:
trait A { self: B => }
trait B { self: A => }
Inheritance using extends does not allow that. Try:
trait A extends B
trait B extends A
error: illegal cyclic reference involving trait A
In the Odersky book, look at section 33.5 (Creating spreadsheet UI chapter) where it mentions:
In the spreadsheet example, class Model inherits from Evaluator and
thus gains access to its evaluation method. To go the other way, class
Evaluator defines its self type to be Model, like this:
package org.stairwaybook.scells
trait Evaluator { this: Model => ...
One additional difference is that self-types can specify non-class types. For instance
trait Foo{
this: { def close:Unit} =>
...
}
The self type here is a structural type. The effect is to say that anything that mixes in Foo must implement a no-arg "close" method returning unit. This allows for safe mixins for duck-typing.
Another thing that has not been mentioned: because self-types aren't part of the hierarchy of the required class they can be excluded from pattern matching, especially when you are exhaustively matching against a sealed hierarchy. This is convenient when you want to model orthogonal behaviors such as:
sealed trait Person
trait Student extends Person
trait Teacher extends Person
trait Adult { this : Person => } // orthogonal to its condition
val p : Person = new Student {}
p match {
case s : Student => println("a student")
case t : Teacher => println("a teacher")
} // that's it we're exhaustive
Section 2.3 "Selftype Annotations" of Martin Odersky's original Scala paper Scalable Component Abstractions actually explains the purpose of selftype beyond mixin composition very well: provide an alternative way of associating a class with an abstract type.
The example given in the paper was like the following, and it doesn't seem to have an elegant subclass correspondent:
abstract class Graph {
type Node <: BaseNode;
class BaseNode {
self: Node =>
def connectWith(n: Node): Edge =
new Edge(self, n);
}
class Edge(from: Node, to: Node) {
def source() = from;
def target() = to;
}
}
class LabeledGraph extends Graph {
class Node(label: String) extends BaseNode {
def getLabel: String = label;
def self: Node = this;
}
}
TL;DR summary of the other answers:
Types you extend are exposed to inherited types, but self-types are not
eg: class Cow { this: FourStomachs } allows you to use methods only available to ruminants, such as digestGrass. Traits that extend Cow however will have no such privileges. On the other hand, class Cow extends FourStomachs will expose digestGrass to anyone who extends Cow .
self-types allow cyclical dependencies, extending other types does not
Let's start with the cyclical dependency.
trait A {
selfA: B =>
def fa: Int }
trait B {
selfB: A =>
def fb: String }
However, the modularity of this solution is not as great as it might first appear, because you can override self types as so:
trait A1 extends A {
selfA1: B =>
override def fb = "B's String" }
trait B1 extends B {
selfB1: A =>
override def fa = "A's String" }
val myObj = new A1 with B1
Although, if you override a member of a self type, you lose access to the original member, which can still be accessed through super using inheritance. So what is really gained over using inheritance is:
trait AB {
def fa: String
def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }
trait B1 extends AB
{ override def fb = "B's String" }
val myObj = new A1 with B1
Now I can't claim to understand all the subtleties of the cake pattern, but it strikes me that the main method of enforcing modularity is through composition rather than inheritance or self types.
The inheritance version is shorter, but the main reason I prefer inheritance over self types is that I find it much more tricky to get the initialisation order correct with self types. However, there are some things you can do with self types that you can't do with inheritance. Self types can use a type while inheritance requires a trait or a class as in:
trait Outer
{ type T1 }
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.
You can even do:
trait TypeBuster
{ this: Int with String => }
Although you'll never be able to instantiate it. I don't see any absolute reason for not being be able to inherit from a type, but I certainly feel it would be useful to have path constructor classes and traits as we have type constructor traits / classes. As unfortunately
trait InnerA extends Outer#Inner //Doesn't compile
We have this:
trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }
Or this:
trait Outer
{ trait Inner }
trait InnerA
{this: Outer#Inner =>}
trait InnerB
{this: Outer#Inner =>}
trait OuterFinal extends Outer
{ val myVal = new InnerA with InnerB with Inner }
One point that should be empathised more is that traits can extends classes. Thanks to David Maclver for pointing this out. Here's an example from my own code:
class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
ScnBase inherits from the Swing Frame class, so it could be used as a self type and then mixed in at the end (at instantiation). However, val geomR needs to be initialised before it's used by inheriting traits. So we need a class to enforce prior initialisation of geomR. The class ScnVista can then be inherited from by multiple orthogonal traits which can themselves be inherited from. Using multiple type parameters (generics) offers an alternative form of modularity.
trait A { def x = 1 }
trait B extends A { override def x = super.x * 5 }
trait C1 extends B { override def x = 2 }
trait C2 extends A { this: B => override def x = 2}
// 1.
println((new C1 with B).x) // 2
println((new C2 with B).x) // 10
// 2.
trait X {
type SomeA <: A
trait Inner1 { this: SomeA => } // compiles ok
trait Inner2 extends SomeA {} // doesn't compile
}
A self type lets you specify what types are allowed to mixin a trait. For example, if you have a trait with a self type Closeable, then that trait knows that the only things that are allowed to mix it in, must implement the Closeable interface.
Update: A principal difference is that self-types can depend on multiple classes (I admit that's a bit corner case). For example, you can have
class Person {
//...
def name: String = "...";
}
class Expense {
def cost: Int = 123;
}
trait Employee {
this: Person with Expense =>
// ...
def roomNo: Int;
def officeLabel: String = name + "/" + roomNo;
}
This allows to add the Employee mixin just to anything that is a subclass of Person and Expense. Of course, this is only meaningful if Expense extends Person or vice versa. The point is that using self-types Employee can be independent of the hierarchy of the classes it depends on. It doesn't care of what extends what - If you switch the hierarchy of Expense vs Person, you don't have to modify Employee.
in the first case, a sub-trait or sub-class of B can be mixed in to whatever uses A. So B can be an abstract trait.

What is the difference between self-types and trait subclasses?

A self-type for a trait A:
trait B
trait A { this: B => }
says that "A cannot be mixed into a concrete class that does not also extend B".
On the other hand, the following:
trait B
trait A extends B
says that "any (concrete or abstract) class mixing in A will also be mixing in B".
Don't these two statements mean the same thing? The self-type seems to serve only to create the possibility of a simple compile-time error.
What am I missing?
It is predominately used for Dependency Injection, such as in the Cake Pattern. There exists a great article covering many different forms of dependency injection in Scala, including the Cake Pattern. If you Google "Cake Pattern and Scala", you'll get many links, including presentations and videos. For now, here is a link to another question.
Now, as to what is the difference between a self type and extending a trait, that is simple. If you say B extends A, then B is an A. When you use self-types, B requires an A. There are two specific requirements that are created with self-types:
If B is extended, then you're required to mix-in an A.
When a concrete class finally extends/mixes-in these traits, some class/trait must implement A.
Consider the following examples:
scala> trait User { def name: String }
defined trait User
scala> trait Tweeter {
| user: User =>
| def tweet(msg: String) = println(s"$name: $msg")
| }
defined trait Tweeter
scala> trait Wrong extends Tweeter {
| def noCanDo = name
| }
<console>:9: error: illegal inheritance;
self-type Wrong does not conform to Tweeter's selftype Tweeter with User
trait Wrong extends Tweeter {
^
<console>:10: error: not found: value name
def noCanDo = name
^
If Tweeter was a subclass of User, there would be no error. In the code above, we required a User whenever Tweeter is used, however a User wasn't provided to Wrong, so we got an error. Now, with the code above still in scope, consider:
scala> trait DummyUser extends User {
| override def name: String = "foo"
| }
defined trait DummyUser
scala> trait Right extends Tweeter with User {
| val canDo = name
| }
defined trait Right
scala> trait RightAgain extends Tweeter with DummyUser {
| val canDo = name
| }
defined trait RightAgain
With Right, the requirement to mix-in a User is satisfied. However, the second requirement mentioned above is not satisfied: the burden of implementing User still remains for classes/traits which extend Right.
With RightAgain both requirements are satisfied. A User and an implementation of User are provided.
For more practical use cases, please see the links at the start of this answer! But, hopefully now you get it.
Self types allow you to define cyclical dependencies. For example, you can achieve this:
trait A { self: B => }
trait B { self: A => }
Inheritance using extends does not allow that. Try:
trait A extends B
trait B extends A
error: illegal cyclic reference involving trait A
In the Odersky book, look at section 33.5 (Creating spreadsheet UI chapter) where it mentions:
In the spreadsheet example, class Model inherits from Evaluator and
thus gains access to its evaluation method. To go the other way, class
Evaluator defines its self type to be Model, like this:
package org.stairwaybook.scells
trait Evaluator { this: Model => ...
One additional difference is that self-types can specify non-class types. For instance
trait Foo{
this: { def close:Unit} =>
...
}
The self type here is a structural type. The effect is to say that anything that mixes in Foo must implement a no-arg "close" method returning unit. This allows for safe mixins for duck-typing.
Another thing that has not been mentioned: because self-types aren't part of the hierarchy of the required class they can be excluded from pattern matching, especially when you are exhaustively matching against a sealed hierarchy. This is convenient when you want to model orthogonal behaviors such as:
sealed trait Person
trait Student extends Person
trait Teacher extends Person
trait Adult { this : Person => } // orthogonal to its condition
val p : Person = new Student {}
p match {
case s : Student => println("a student")
case t : Teacher => println("a teacher")
} // that's it we're exhaustive
Section 2.3 "Selftype Annotations" of Martin Odersky's original Scala paper Scalable Component Abstractions actually explains the purpose of selftype beyond mixin composition very well: provide an alternative way of associating a class with an abstract type.
The example given in the paper was like the following, and it doesn't seem to have an elegant subclass correspondent:
abstract class Graph {
type Node <: BaseNode;
class BaseNode {
self: Node =>
def connectWith(n: Node): Edge =
new Edge(self, n);
}
class Edge(from: Node, to: Node) {
def source() = from;
def target() = to;
}
}
class LabeledGraph extends Graph {
class Node(label: String) extends BaseNode {
def getLabel: String = label;
def self: Node = this;
}
}
TL;DR summary of the other answers:
Types you extend are exposed to inherited types, but self-types are not
eg: class Cow { this: FourStomachs } allows you to use methods only available to ruminants, such as digestGrass. Traits that extend Cow however will have no such privileges. On the other hand, class Cow extends FourStomachs will expose digestGrass to anyone who extends Cow .
self-types allow cyclical dependencies, extending other types does not
Let's start with the cyclical dependency.
trait A {
selfA: B =>
def fa: Int }
trait B {
selfB: A =>
def fb: String }
However, the modularity of this solution is not as great as it might first appear, because you can override self types as so:
trait A1 extends A {
selfA1: B =>
override def fb = "B's String" }
trait B1 extends B {
selfB1: A =>
override def fa = "A's String" }
val myObj = new A1 with B1
Although, if you override a member of a self type, you lose access to the original member, which can still be accessed through super using inheritance. So what is really gained over using inheritance is:
trait AB {
def fa: String
def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }
trait B1 extends AB
{ override def fb = "B's String" }
val myObj = new A1 with B1
Now I can't claim to understand all the subtleties of the cake pattern, but it strikes me that the main method of enforcing modularity is through composition rather than inheritance or self types.
The inheritance version is shorter, but the main reason I prefer inheritance over self types is that I find it much more tricky to get the initialisation order correct with self types. However, there are some things you can do with self types that you can't do with inheritance. Self types can use a type while inheritance requires a trait or a class as in:
trait Outer
{ type T1 }
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.
You can even do:
trait TypeBuster
{ this: Int with String => }
Although you'll never be able to instantiate it. I don't see any absolute reason for not being be able to inherit from a type, but I certainly feel it would be useful to have path constructor classes and traits as we have type constructor traits / classes. As unfortunately
trait InnerA extends Outer#Inner //Doesn't compile
We have this:
trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }
Or this:
trait Outer
{ trait Inner }
trait InnerA
{this: Outer#Inner =>}
trait InnerB
{this: Outer#Inner =>}
trait OuterFinal extends Outer
{ val myVal = new InnerA with InnerB with Inner }
One point that should be empathised more is that traits can extends classes. Thanks to David Maclver for pointing this out. Here's an example from my own code:
class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
ScnBase inherits from the Swing Frame class, so it could be used as a self type and then mixed in at the end (at instantiation). However, val geomR needs to be initialised before it's used by inheriting traits. So we need a class to enforce prior initialisation of geomR. The class ScnVista can then be inherited from by multiple orthogonal traits which can themselves be inherited from. Using multiple type parameters (generics) offers an alternative form of modularity.
trait A { def x = 1 }
trait B extends A { override def x = super.x * 5 }
trait C1 extends B { override def x = 2 }
trait C2 extends A { this: B => override def x = 2}
// 1.
println((new C1 with B).x) // 2
println((new C2 with B).x) // 10
// 2.
trait X {
type SomeA <: A
trait Inner1 { this: SomeA => } // compiles ok
trait Inner2 extends SomeA {} // doesn't compile
}
A self type lets you specify what types are allowed to mixin a trait. For example, if you have a trait with a self type Closeable, then that trait knows that the only things that are allowed to mix it in, must implement the Closeable interface.
Update: A principal difference is that self-types can depend on multiple classes (I admit that's a bit corner case). For example, you can have
class Person {
//...
def name: String = "...";
}
class Expense {
def cost: Int = 123;
}
trait Employee {
this: Person with Expense =>
// ...
def roomNo: Int;
def officeLabel: String = name + "/" + roomNo;
}
This allows to add the Employee mixin just to anything that is a subclass of Person and Expense. Of course, this is only meaningful if Expense extends Person or vice versa. The point is that using self-types Employee can be independent of the hierarchy of the classes it depends on. It doesn't care of what extends what - If you switch the hierarchy of Expense vs Person, you don't have to modify Employee.
in the first case, a sub-trait or sub-class of B can be mixed in to whatever uses A. So B can be an abstract trait.