Фундаментальное качество, которое отличает наращиваемые модификации (поскольку терминология в любом случае используется в scala), заключается в том, что на «супер» влияет динамически в зависимости от того, как смешана эта черта, тогда как в общем случае супер является статически определенной целью.
Если вы напишите
abstract class Bar { def bar(x: Int): Int }
class Foo extends Bar { def bar(x: Int) = x }
тогда для Foo "супер" всегда будет Bar.
Если вы напишите
trait Foo1 extends Foo { abstract override def bar(x: Int) = x + super.bar(x) }
Тогда для этого метода super остается неизвестным, пока класс не будет создан.
trait Foo2 extends Foo { abstract override def bar(x: Int) = x * super.bar(x) }
scala> (new Foo with Foo2 with Foo1).bar(5)
res0: Int = 30
scala> (new Foo with Foo1 with Foo2).bar(5)
res1: Int = 50
Почему это интересно? Иллюстративным примером могут быть некоторые данные, которые вы хотите сжать, зашифровать и подписать цифровым способом. Возможно, вы захотите сжать, затем зашифровать, затем подписать, или вы можете захотеть зашифровать, затем подписать, затем сжать и т. Д. Если вы проектируете свои компоненты таким образом, вы можете создать экземпляр настраиваемого объекта с точно такими битами, которые вы хотите организовать так, как вы хотите.