Scala a commencé à apprendre la langue pour le plaisir et j’essaie toujours de la comprendre. Si je comprends bien les traits de Scala, ils ressemblent aux interfaces Java, sauf que certaines méthodes peuvent avoir une implémentation.
Java 8 ajoute des interfaces pouvant avoir des méthodes par défaut pour lesquelles une implémentation peut être fournie.
Quelles sont les similitudes et les différences entre les interfaces Java 8 et les traits Scala?
Les motivations pour les méthodes par défaut de Java 8 et les traits Scala sont différentes.
Le premier a été introduit pour prendre en charge l'évolution sécurisée des API et une forme limitée d'héritage multiple. En exploitant les idiomes de programmation fonctionnels dans Project Lambda, il a été avantageux d’ajouter, par exemple, une méthode forEach(lambda)
à l'interface Java.util.Collection
sans modifier tous les implémenteurs possibles (ce qui est en fait impossible à faire sans interrompre la compatibilité ascendante). Comme effet secondaire, cela offrait également une forme de composition de mixin .
Les traits de scala ont été conçus à partir de zéro comme éléments de base pour la composition en composants modulaires. Ils sont compatibles avec l'héritage multiple et n'ont pas de problème de diamant en raison de règles strictes sur l'ordre d'évaluation des mixages dus à la linéarisation. Ils prennent également en charge state, peuvent faire référence à la classe d'implémentation et placer des restrictions sur le type pouvant les mélanger. Regardez la bibliothèque de collections Scala où les traits sont utilisés à fond.
Notez que avec scala 2.12.0 RC1 (septembre 2016) , Trait
est maintenant compilé en une interface.
Scala 2.12 consiste à exploiter au mieux les nouvelles fonctionnalités de Java 8
Avec Java 8 permettant des méthodes concrètes dans les interfaces, Scala 2.12 est capable de compiler un trait en une seule interface.
Avant, un trait était représenté par une classe contenant les implémentations de méthodes et une interface.
Notez que le compilateur a encore un peu de magie à exécuter en coulisse, de sorte qu'il faut faire attention si un trait doit être implémenté en Java.
(En bref, si un trait fait l'une des choses suivantes, ses sous-classes requièrent un code synthétique: définition de champs, appel de super instructions d'initialisation dans le corps, extension d'une classe, utilisation de la linéarisation pour trouver des implémentations dans le bon trait de droite.)
Voir scala PR 5003 more la différence de mise en œuvre.
Sur la similitude, les deux peuvent avoir des méthodes par défaut,
Côté différences, nous pouvons ajouter des traits à une seule instance, et non à la classe entière. Exemple:
trait A { def m = ??? }
class B
new B() with A
De même, nous pouvons continuer à ajouter des couches de trait sur une instance.