Si el rasgo A extiende a B, entonces mezclar en A le da exactamente B más lo que A agrega o extiende. Por el contrario, si el rasgo A tiene una autorreferencia que se escribe explícitamente como B, entonces la clase padre última también debe mezclar B o un tipo descendiente de B (y mezclarlo primero , lo cual es importante).
Esa es la diferencia más importante. En el primer caso, el tipo preciso de B se cristaliza en el punto A lo extiende. En el segundo, el diseñador de la clase principal decide qué versión de B se utiliza, en el punto donde se compone la clase principal.
Otra diferencia es donde A y B proporcionan métodos del mismo nombre. Donde A extiende a B, el método de A anula a B. Cuando A se mezcla después de B, el método de A simplemente gana.
La autorreferencia mecanografiada te da mucha más libertad; El acoplamiento entre A y B está suelto.
ACTUALIZAR:
Como no tiene claro el beneficio de estas diferencias ...
Si usa la herencia directa, entonces crea el rasgo A que es B + A. Has establecido la relación en piedra.
Si usa una autorreferencia escrita, cualquiera que quiera usar su rasgo A en la clase C podría
- Mezcle B y luego A en C.
- Mezcle un subtipo de B y luego A en C.
- Mezcle A en C, donde C es una subclase de B.
Y este no es el límite de sus opciones, dada la forma en que Scala le permite instanciar un rasgo directamente con un bloque de código como su constructor.
En cuanto a la diferencia entre el método ganador de A , porque A se mezcla en último lugar, en comparación con A que extiende B, considere esto ...
Cuando se mezcla una secuencia de rasgos, cada vez que foo()se invoca el método , el compilador va al último rasgo mezclado para buscar foo(), luego (si no se encuentra), atraviesa la secuencia hacia la izquierda hasta que encuentra un rasgo que implementa foo()y utiliza ese. A también tiene la opción de llamar super.foo(), que también atraviesa la secuencia hacia la izquierda hasta que encuentra una implementación, y así sucesivamente.
Entonces, si A tiene una autorreferencia escrita a B y el escritor de A sabe que B implementa foo(), A puede llamar super.foo()sabiendo que si nada más proporciona foo(), B lo hará. Sin embargo, el creador de la clase C tiene la opción de eliminar cualquier otro rasgo en el que se implemente foo(), y A lo obtendrá en su lugar.
De nuevo, esto es mucho más potente y menos limitante que A que se extiende B y llamando directamente a la versión de B de foo().