Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo...

46
Subtype Polymorphism

Transcript of Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo...

Page 1: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtype Polymorphism

Page 2: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

• Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch

Page 3: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Conversioni di tipo

• Variabile: locazione con un tipo associato Tipo della variabile determinato dal compilatore

guardando la dichiarazione Una variabile di tipo reference contiene un riferimento

ad un oggetto

• Oggetto: istanza di una classe Tipo dell’oggetto: la classe che lo crea Determinato a run time

• Una variabile può assumere come valori riferimenti ad oggetti di classi diverse

Continua…

Page 4: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Conversioni di tipo

• È possibile assegnare un riferimento di tipo classe ad una variabile di tipo interfaccia purchè la classe implementi l’interfaccia

BankAccount account = new BankAccount(10000);Measurable x = account; // OK

Coin dime = new Coin(0.1, "dime");Measurable y = dime; // OK

Continua…

Page 5: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Conversioni di tipo

• La conversione è lecita solo in determinate situazioni

• Problema: Rectangle non implementa Measurable

Measurable x = new Rectangle(5, 10, 20, 30); // ERRORE

Page 6: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping

• Subtyping (<:) Una relazione che permette di decidere quando è

legittimo convertire un tipo riferimento in un altro

• Chi decide cosa/quando è legittimo? il compilatore!

• Per il momento la regola è:

Continua…

T1 <: T2 sse T1 è una classe, T2 è una interfaccia T1 implementa T2.

Page 7: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping

• Principio di sostituibilità Un riferimento di un sottotipo può essere usato

ovunque ci si aspetti un riferimento di un supertipo

• Le regole di sottotipo devono garantire la correttezza del principio di sostituibilità

Continua…

Page 8: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping

• La regola C <: I se C implementa I

• Principio di sostituibilità un riferimento di tipo C può sempre essere usato dove

si attende un riferimento di tipo I

• E’ ragionevole perché se C implementa I , C definisce public tutti i metodi

dichiarati da I Quindi tutti le invocazioni di metodo possibili per I sono

supportate da C

Continua…

Page 9: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping e regole di typing

• Regola di assegnamento Un riferimento di tipo T1 si puo sempre assegnare ad una variabile

di tipo T2 sse T1 <: T2 Un riferimento di tipo classe può sempre essere assegnato ad una

variabile di tipo interfaccia (se la classe implementa l’interfaccia)

• Regola di passaggio di parametri Un riferimento di tipo T1 si puo sempre passare per un parametro

di tipo T2 sse T1 <: T2 Un riferimento di tipo classe può sempre essere passato per un

parametro di tipo interfaccia (se la classe implementa l’interfaccia)

Page 10: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Domanda

• Data l’implementazione generica della classe DataSet, che oggetti possiamo passare come argomento per x ?

public class DataSet { public void add(Measurable x) { ... }

... }

Page 11: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Risposta

• Qualunque istanza di una una classe che implementa Measurable

Page 12: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Polimorfismo – dynamic dispatch

• Una variabile di tipo interfaccia ha sempre come valore un riferimento di una classe che implementa l’interfaccia

Continua…

Measurable x;x = new BankAccount(10000);x = new Coin(0.1, "dime");

Page 13: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Polimorfismo – dynamic dispatch

• Possiamo invocare ognuno dei metodi dell’interfaccia:

• Quale metodo invoca?

double m = x.getMeasure();

Page 14: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Polimorfismo – dynamic dispatch

• Dipende dal riferimento corrente memorizzato nella variabile 

• Se x riferisce un BankAccount, invoca il metodo BankAccount.getMeasure()

• Se x riferisce un Coin, invoca il metodo Coin.getMeasure()

• Polimorfismo (molte forme): il comportamento varia, e dipende dal tipo dinamico

della variabile

Continua…

Page 15: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Domande

5. È impossibile costruire un oggetto di tipo Measurable.Perché?

6. Perché invece é possibile dichiarare una variabile di tipo Measurable?

Page 16: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Risposte

5. Measurable è una interfaccia. Le interfacce non hanno campi o implementazione di metodo.

6. Perché Measurable è un tipo: la variabile non riferirà mai una istanza di Measurable, (le interfacce non hanno istanze) ma piuttosto oggetto di una qualche classe che implementa l’interfaccia Measurable.

Continua…

Page 17: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

• Costruiamo una applicazione per disegnare un insieme di forme geometriche contenute in una componente grafico: definiamo GWin, una classe che descrive un

contenitore di forme geometriche disegnate mediante una invocazione del metodo paint()

per esemplificare, consideriamo due tipi di forme: Car e Smiley

Ancora un esempio

Page 18: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Forme grafiche

class Car{ . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . }} class Smiley

{ . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . }}

Page 19: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

• Un contenitore di Cars e Smileys

GWin

/** Una finestra che contiene un insieme Cars e Smileys */ class GWin { /** Disegna tutte le forme di questo component */ public void paint(){ /* disegna su g */ } /**

Componente grafica su cui disegnare */

private Graphics2D g; }

Page 20: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Domanda

• Che struttura utilizziamo per memorizzare le forme contenute nella GWin?

• Come definiamo il metodo paint() in modo che disegni tutte le forme della componente?

Page 21: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Risposte

• definiamo una nuova interfaccia: Shape

• Ridefiniamo le classi Car e Smiley in modo che implementino Shape

• Memorizziamo gli oggetti della componente in una ArrayList<Shape>

interface Shape { void draw(Graphics2D g); }

Page 22: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Car e Smiley implementano Shape

class Car implements Shape

{ . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . }} class Smiley implements Shape

{ . . . public void draw(Graphics2D g) { // Istruzioni per il disegno . . . }}

Page 23: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Mantiene una ArrayList<Shape>

GWin

class GWin { private Graphics2D g; private ArrayList<Shape> shapes; // crea una GWin con un insieme di forme public GWin(Shape... shapes) { Graphics2D g = new Graphics2D();

this.shapes = new ArrayList<Shape>(); for (Shape s:shapes) this.shapes.add(s); } // disegna tutte le componenti della GWin public void paint() {

for (Shape s:shapes) s.draw(g); } }

Page 24: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Diagramma delle Classi

Car

GWin

Smiley

Shape

Car

Page 25: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

So long, for today

Page 26: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Polimorfismo – dynamic dispatch

• Dynamic dispatch: Il metodo da invocare per rispondere ad un

messaggio è deciso a tempo di esecuzione

Page 27: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Dynamic dispatch in GWin

class GWin { . . . private ArrayList<Shape> shapes; . . . public void paint() {

// disegna tutte le componenti della GWin // il metodo invocato effettivamente da ogni

// messaggio s.draw(g) dipende dalla classe // di cui s è istanza ed è deciso a runtime

for (Shape s:shapes) s.draw(g); } . . . . }

Page 28: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Dynamic dispatch vs overloading

• Dynamic dispatch: Il metodo da invocare per rispondere ad un

messaggio è deciso a tempo di esecuzione

• Notiamo bene Il metodo da invocare è deciso a runtime il compilatore decide se esiste un metodo da invocare

• Overloading: Nel caso esista più di un metodo, il compilatore

decide staticamente il tipo del metodo da invocare

Page 29: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Dynamic dispatch vs overloading

interface I { public String m(boolean b); public String m(double d); } class A implements I { public String m(boolean b) { return “A.m(boolean)”; } public String m(double d) { return “A.m(double)”; } }

class B implements I { public String m(boolean b) { return “B.m(boolean)”; } public String m(double d) { return “B.m(double)”; } }

Page 30: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Dynamic dispatch vs overloading

class Client { public void static show(I x) { // tipo del metodo invocato = m(boolean) // deciso dal compilatore staticamente // metodo invocato deciso dinamicamente // in funzione del tipo dell’argomento // passato per x

System.out.println( x.m(false) ); } }

Page 31: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Domanda

• Che cosa hanno in comune i meccanismi di overloading e di dynamic dispatch? In cosa sono diversi?

Page 32: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

• Entrambi i meccanismi contribuiscono a decidono quale metodo eseguire in risposta ad un messaggio, ma• Nell’overloading scelta è relativa al tipo del metodo,

ed è fatta in compilazione guardando il tipo dei parametri

• Nel dynamic dispatch la scelta è relativa al corpo del metodo, ed è fatta in esecuzione guardando il tipo dell’oggetto che riceve il messaggio

Risposta

Page 33: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping e sostituibilità

• Principio di sostituibilità Un riferimento di un sottotipo può essere usato

ovunque ci si aspetti un riferimento di un supertipo

• Le regole di sottotipo garantiscono la correttezza del principio di sostituibilità Tutti i metodi del supertipo devono essere

implementati dal sottotipo Il sottotipi può avere anche altri metodi

Continua…

Page 34: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping e perdita di informazione

• Principio di sostituibilità Un riferimento di un sottotipo può essere usato

ovunque ci si aspetti un riferimento di un supertipo

• Può causare perdita di informazione nel contesto in cui ci aspettiamo il supertipo, non

possiamo usare solo I metodi del supertipo perdiamo la possibilità di utilizzare gli eventuali metodi

aggiuntivi del sottotipo

Continua…

Page 35: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Car e Smiley implementano Shape

class Smiley implements Shape

{ . . .public void draw(Graphics2D g){ . . . }public String mood() {. . . }

}

class Car implements Shape

{ . . .public void draw(Graphics2D g){ . . . }public String brand() {. . . }

}

Page 36: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping e perdita di informazione

• Consideriamo

public static void printBrand(List<Shape> l)

{ for (Shape s : l)

// stampa la marca di tutte le macchine di l

// ???

}

Continua…

Page 37: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Subtyping e perdita di informazione

• Certamente non possiamo fare così …

public static void printBrand(List<Shape> l)

{ for (Shape s : l)

// stampa la marca di tutte le macchine di l

System.out.println( s.brand() ); // TYPE ERROR!

}

Continua…

Page 38: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Cast

• Permette di modificare il tipo associato ad una espressione

• Un cast è permesso dal compilatore solo se applica conversioni tra tipi compatibili

• Compatibili = sottotipi (per il momento)

• Anche quando permesso dal compilatore, un cast può causare errore a run time

• Se s non è un Car errore a run time

Continua…

((Car)s).brand()

Page 39: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Cast

• Tipo statico e tipo dinamico di una variabile tipo statico: quello dichiarato tipo dinamico: il tipo del riferimento assegnato alla

variabile

• (T)var causa errore in compilazione

se T non è compatibile con il tipo statico di var in esecuzione (ClassCastException)

se T non è compatibile con il tipo dinamico di var

Continua…

Page 40: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Cast

• OK: Car sottotipo di Shape

• Compila correttamente il tipo dichiarato di s è Shape Car e Shape sono compatibili

• Esegue correttamente s è un Car (il tipo dinamico di s è Car)

Shape s = new Car();

Continua…

Car c = (Car) s

Page 41: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Cast

• OK: Car sottotipo di Shape

• Compila correttamente il tipo dichiarato di s è Shape Smiley e Shape sono compatibili

• Errore a run time s non è uno Smiley

Shape s = new Car();

Continua…

Smiley c = (Smiley) s

Page 42: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Cast

• Attenzione anche qui …

public static void printBrand(List<Shape> l)

{ for (Shape s : l)

// ClassCastException se s instance of Smiley

System.out.println( ((Car)s.)brand() );

}

Continua…

Page 43: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

instanceof

• Permette di determinare il tipo dinamico di una variabile

• Quindi permette di evitare errori in esecuzione

• Esegue correttamente, perchè x è sicuramente un T

x istanceof T è true solo se x ha tipo dinamico T

if (x instanceof T) return (T) x

Page 44: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Cast

• Questo, finalmente, è corretto

public static void printBrand(List<Shape> l)

{ for (Shape s : l)

if (s instanceof Car)

System.out.println( ((Car)s.)brand() );

}

Page 45: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Domanda

• E se volessimo disegnare solo le Shapes che sono Cars?

Page 46: Subtype Polymorphism. Interfacce e subtype polimorfismo Tipi, sottotipi e conversioni di tipo Polimorfismo e dinamic dispatch.

Risposta

// disegna tutte le Cars della GWin

public void paint(){ for (Shape c:shapes)

if (c instanceof Car) c.draw(g); }