Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Selfreferencing Generics

Tags:

scala

I've searched a bit around but I was not able to find an example of such a structure:

Person[P <: Person[P]]

that is explained in a way I understand.

How does this resolve? It kinda looks like an endless recursion to me, but it seems I am wrong with that conclusion.

like image 518
Cola Colin Avatar asked Feb 18 '13 15:02

Cola Colin


People also ask

What is self reference in C#?

Self Referential structures are those structures that have one or more pointers which point to the same type of structure, as their member.

What is self in Java?

A self type refers to the type on which a method is called (more formally called the receiver). If a self type is used in an inherited method, it represents a different type in each class that declares or inherits that method–namely that specific class, no matter whether it declared or inherited the method.

Are there generics in PHP?

Generics are an important step towards PHP maturing as a gradually-typed language - a direction in which PHP is already moving, with the addition of scalar type-hints, and return type-hints, in PHP 7.


2 Answers

The structure itself is explained in the Twitter Scala School and is called F-bounded polymorphism.

// you define it like this
trait X extends Person[X]

// it then gets expanded to this
trait Person[X extends Person[X]]

This structure is used when the trait needs to have a reference to the type of the object it is extending. If the Scala school explanation is not enough you can search the internet for 'F-bounded polymorphism'

like image 158
EECOLOR Avatar answered Sep 23 '22 19:09

EECOLOR


This is sometimes called a self type (not to be confused with Scala's explicitly typed self-references) and it is usually used in order to have method signatures that are strong enough to express that the method works with objects of the same type as the receiver.

Let's look at an example. Say, you have a base trait Animal with a generic breed method that takes another Animal and returns an Animal.

trait Animal {
  def breed(a: Animal): Animal
}

Ok, but what you actually want is a breed method that expresses that every concrete animal only breeds with animals of the same class and also returns an animal of the same class. The following implementation

class Cow extends Animal {
  def breed(c: Cow) = new Cow
}

is not possible, because this breed's signature doesn't match. Overriding is also not possible, because you would need to change the argument type covariantly, which is forbidden.

Self-types to the rescue:

trait Animal[A <: Animal[A]] {
  def breed(a: A): A
}

class Cow extends Animal[Cow] {
  def breed(c: Cow) = new Cow
}

As EECOLOR already pointed out, the type theory behind it is called F-bounded polymorphism.

like image 30
Malte Schwerhoff Avatar answered Sep 22 '22 19:09

Malte Schwerhoff