Un altro termine potrebbe essere " invio dinamico ". Di seguito è riportato un esempio che utilizza C # (un po 'non idiomatico)
Supponiamo di avere il seguente tipo di elenco:
public abstract class List<T> {
public abstract bool isEmpty();
public abstract T head();
public abstract List<T> tail();
}
class Empty<T> : List<T> {
public Empty() { }
public override bool isEmpty() { return true; }
public override T head() {
throw new ApplicationException("head of empty list");
}
public override List<T> tail() {
throw new ApplicationException("tail of empty list");
}
}
class Cons<T> : List<T> {
private T head;
private List<T> tail;
public Cons(T head, List<T> tail) {
this.head = head;
this.tail = tail;
}
public override bool isEmpty() { return false; }
public override T head() { return head; }
public override List<T> tail() { return tail; }
}
Potresti implementare una funzione di lunghezza come segue:
int length(List<T> xs) {
if(xs.isEmpty()) {
return 0;
} else {
return 1 + length(xs.tail());
}
}
In alternativa, utilizzando l'invio dinamico come suggerisce Kent Beck, potremmo eliminare il condizionale aggiungendo length
come metodo di List<T>
.
public abstract class List<T> {
/* ... */
public abstract int length();
}
class Empty<T> : List<T> {
/* ... */
public override int length() {
return 0;
}
}
class Cons<T> : List<T> {
/* ... */
public override int length() {
return 1 + tail.length();
}
}
Ciò aumenta la flessibilità perché ora possiamo aggiungere un'altra classe con la sua implementazione di length
che può essere più intelligente della nostra funzione length
.
class Concat<T> : List<T> {
private List<T> left, right;
public Concat(List<T> left, List<T> right) {
this.left = left;
this.right = right;
}
/* ... */
public override int length() {
return left.length() + right.length();
}
}
Per quanto riguarda un po ', ci sono problemi con la definizione di length
in Cons<T>
che causerà l'utilizzo di molto spazio nello stack e probabilmente produrrà un overflow dello stack in uso reale. Il problema è che non è scritto in un modulo ricorsivo di coda . Questo è facilmente corretto, ma anche se corretto, dal momento che praticamente nessun linguaggio OO garantisce l'eliminazione delle chiamate tail, i benefici che Kent Beck menziona non possono essere raggiunti in questo esempio. In altre parole, la mancanza di un'eliminazione di chiamata di coda ostacola in modo significativo uno dei principali vantaggi dello stile OO.