Polymorfismus

V principu jsou dvě formy polymorfismu: podtypy a generické.

Podtypy (Subtyping)

Vlasnost, která nám umožňuje pojmenovat nějakou konkrétní metodu identickým jménem, přičemž její implementace se může v jednotlivých třídách hierarchie tříd lišit.

A je pod-typ (subtype) B (A <: B)

  • Scala: class A extends B
  • Java: class A extends B nebo class A implements B
  • (C++): class A : public B
  • Python: class A(B)
  • Kotlin: class A : B

B je nad-typ (supertype) A (B >: A)

Podtypy jsou tranzitivní: pokud A <: B a C <: A pak C <: B.

V java-like jazycích je každá reference podtypem Object

we can’t use the static type information to resolve the method

Generické (Generics)

instances of a function or a class are created by type parameterization.

Type erasure

V Javě/Scale se setkáme s takzvaným type erasure. Jedná se o odstranění informace o generickém typu překladačem při vytváření bajtkódu. To má několik důsledků – striktní typová kontrola je prováděna v době překladu (compile time), ovšem typová informace (například o typu prvků kontejneru) je v čase běhu (runtime) ztracena.

Z toho plyne, že v ge­ne­rické třídě s ty­po­vým pa­ra­me­t­rem T ne­mů­žeme během run-time vy­tvo­řit novou in­stanci třídy T, pro­tože nevíme, jakou hod­notu T má.

C++, C# nepoužívají type erasure

Omezení (Bounds)

Typová parametrizace může být “bounded” neboli omezená. Můžeme omezit typy, které generická metoda akceptuje.


Substituční princip

Proměnné daného typu může být přiřazena hodnota jakéhokoliv podtypu daného typu

val a: Animal = new Dog("Angie")

Metodu s parametrem daného typu lze použít s argumentem jakéhokoli podtypu daného typu

Liskov Substitution Principle

Let Φ(x) be a property provable about objects x of type A. Then Φ(y) should be true for objects y of type B where B is a subtype of A (B <: A). 1

The Get and Put Principle

Use upper bound when you only get values out of a structure, use lower bound when you only put values into a structure, and don't use type bounds when you both get and put.

PECS principle

Producer Extends, Consumer Super


Variance

Variance je obecný pojem, který říká, jakým způsobem funguje subtyping u komplexních (např. generické kolekce, funkcí) typů.

Dog <: Animal
List[Cat] <: List[Animal]

Variance může být trojího druhu:

  • Invariance říká, že mezi komplexními typy není žádný vztah. f je invariantní, pokud není kovariantní ani kontravariantní

  • Kovariance umožňuje nahradit komplexní typ jeho podtypem. f je konvariatní: pokud A <: B, pak f(A) <: f(B)

  • Kontravariance umožňuje nahradit komplexní typ jeho nadtypem. f je kontravariantní: pokud A <: B, pak f(B) <: f(A)

Teď už by mělo být zřejmé, že ačkoliv typy v kolekci podporují subtyping (např. Cat → Animal), tak kolekce samotné jsou v Javě invariantní: seznam List není podtypem List.

V některých jazycích, jako například Dart, jsou kolekce s generikou (a generika obecně) kovariantní, tedy že List je podtypem List a A<Cat, Dog> je podtypem B<Animal, Animal> (oboje se společným předkem X<Y, Z>).

f může být například kolekce v Javě https://stackoverflow.com/questions/8481301/covariance-invariance-and-contravariance-explained-in-plain-english

Hezké vysvětlení k pochopení KONTRAVARIANCE: https://dev.to/vitornovictor/contravariance-in-the-real-world-29l


  1. Behavioral Notion of Subtyping, Barbara Liskov and Jeannette Wing, ACM TOPLAS 16 (6), 1994  

Související