Se il tratto A si estende in B, la miscelazione in A ti dà esattamente B più qualunque cosa A aggiunga o si estenda. Al contrario, se la caratteristica A ha un riferimento personale che è esplicitamente tipizzato come B, allora anche la classe genitore finale deve mescolarsi in B o un tipo discendente di B (e mescolarlo per primo , il che è importante).
Questa è la differenza più importante. Nel primo caso, il tipo preciso di B viene cristallizzato nel punto A che lo estende. Nel secondo, il progettista della classe genitore decide quale versione di B viene utilizzata, nel punto in cui è composta la classe genitore.
Un'altra differenza è dove A e B forniscono metodi con lo stesso nome. Dove A estende B, il metodo A ignora B. Dove A viene mischiato dopo B, il metodo A vince semplicemente.
L'auto-riferimento tipizzato ti dà molta più libertà; l'accoppiamento tra A e B è lento.
AGGIORNARE:
Dal momento che non sei chiaro sul vantaggio di queste differenze ...
Se usi l'ereditarietà diretta, crei il tratto A che è B + A. Hai impostato la relazione in pietra.
Se usi un riferimento personale tipizzato, allora chiunque voglia usare il tratto A in classe C potrebbe farlo
- Mescola B e poi A in C.
- Mescola un sottotipo di B e poi A in C.
- Mescola A in C, dove C è una sottoclasse di B.
E questo non è il limite delle loro opzioni, dato il modo in cui Scala ti consente di creare un'istanza di un tratto direttamente con un blocco di codice come suo costruttore.
Per quanto riguarda la differenza tra il metodo di A vincente , poiché A è mischiato per ultimo, rispetto ad A che si estende B, considera questo ...
Quando mescoli in una sequenza di tratti, ogni volta che foo()
viene invocato il metodo , il compilatore passa all'ultimo tratto mischiato a cercare foo()
, quindi (se non trovato), attraversa la sequenza a sinistra fino a quando non trova un tratto che implementa foo()
e usa quello. A ha anche l'opzione di chiamare super.foo()
, che attraversa anche la sequenza a sinistra fino a quando non trova un'implementazione, e così via.
Quindi se A ha un auto-riferimento tipizzato a B e lo scrittore di A sa che B implementa foo()
, A può chiamare super.foo()
sapendo che se non altro fornisce foo()
, B lo farà. Tuttavia, il creatore di classe C ha la possibilità di eliminare qualsiasi altro tratto in cui si implementa foo()
e A invece lo otterrà.
Ancora una volta, questo è molto più potente e meno limitante di A estendendo B e chiamando direttamente la versione di B di foo()
.