Qu'est-ce qu'un trait scellé?

332

Les classes scellées sont décrites dans «Programmation en Scala», mais pas les traits scellés. Où puis-je trouver plus d'informations sur un trait scellé?

J'aimerais savoir si un trait scellé est identique à une classe scellée? Ou, sinon, quelles sont les différences? Quand est-ce une bonne idée d'utiliser un trait scellé (et quand non)?

John Threepwood
la source

Réponses:

473

Un sealedtrait ne peut être étendu que dans le même fichier que sa déclaration.

Ils sont souvent utilisés pour fournir une alternative à enums. Puisqu'ils ne peuvent être étendus que dans un seul fichier, le compilateur connaît tous les sous-types possibles et peut en raisonner.

Par exemple avec la déclaration:

sealed trait Answer
case object Yes extends Answer
case object No extends Answer

Le compilateur émettra un avertissement si une correspondance n'est pas exhaustive:

scala> val x: Answer = Yes
x: Answer = Yes

scala> x match {
     |   case No => println("No")
     | }
<console>:12: warning: match is not exhaustive!
missing combination            Yes

Vous devez donc utiliser des traits scellés (ou une classe abstraite scellée) si le nombre de sous-types possibles est fini et connu à l'avance. Pour plus d'exemples, vous pouvez consulter les implémentations de liste et d' options .

paradigmatique
la source
113
il m'a fallu six mois pour arriver au hasard ici et comprendre comment remplacer Java Enum dans Scala.
sscarduzio
1
très agréable ! et non seulement finie et connue à l'avance, mais aussi partie d'un contexte restreint (scellé?) où il est logique de vérifier tous les sous-types possibles comme oui | non, même | bizarre etc ...
Mário de Sá Vera
90

un trait scellé est le même qu'une classe scellée?

En ce qui concerne sealed, oui. Ils partagent les différences normales entre traitet class, bien sûr.

Ou, sinon, quelles sont les différences?

Discutable.

Quand est-ce une bonne idée d'utiliser un trait scellé (et quand non)?

Si vous en avez un sealed class X, vous devez vérifier Xainsi que les sous-classes. Il n'en va pas de même pour sealed abstract class Xou sealed trait X. Donc, vous pourriez le faire sealed abstract class X, mais c'est beaucoup plus verbeux que juste traitet pour peu d'avantages.

Le principal avantage d'utiliser un abstract classsur un traitest qu'il peut recevoir des paramètres. Cet avantage est particulièrement pertinent lors de l'utilisation de classes de types. Disons que vous voulez construire un arbre trié, par exemple. Vous pouvez écrire ceci:

sealed abstract class Tree[T : Ordering]

mais vous ne pouvez pas faire ceci:

sealed trait Tree[T : Ordering]

puisque les limites de contexte (et les limites de vue) sont implémentées avec des paramètres implicites. Étant donné que les traits ne peuvent pas recevoir de paramètres, vous ne pouvez pas le faire.

Personnellement, je préfère sealed traitet l'utilise à moins qu'une raison particulière ne me fasse utiliser un sealed abstract class. Et je ne parle pas de raisons subtiles, mais de raisons que vous ne pouvez pas ignorer, telles que l'utilisation de classes de types.

Daniel C. Sobral
la source
"puisque les limites de contexte (et les limites de vue) sont implémentées avec des paramètres implicites." - Pouvez-vous développer sur ce sujet?
Ruby
@ Ruby - réponse assez tardive, mais au cas où vous ou quelqu'un d'autre serait intéressé: le contexte bounding ( [A: F]) ne fonctionne pas de la même manière que les contraintes de variance. C'est plutôt le sucre syntaxique qui demande une F[A]portée implicite . Il est généralement utilisé pour invoquer des instances de classe d'une manière un peu plus subtile et plus facile à lire qu'un paramètre implicite ( (implicit fa: F[A])), mais il fonctionne toujours de la même manière sous le capot, et comme le souligne Daniel, les traits ne sont pas adaptés. cette.
mirichan
54

Sur le blog daily-scala :

Lorsqu'un trait est "scellé", toutes ses sous-classes sont déclarées dans le même fichier et cela rend l'ensemble des sous-classes fini, ce qui permet certaines vérifications du compilateur.

Brian Agnew
la source
Je vous remercie. Avec «toutes ses sous-classes», cela signifie des classes et des traits?
John Threepwood
@John - Je n'ai pas essayé, mais je soupçonne des cours. Le point sur le scellement est que tout est défini au sein de cette unité source
Brian Agnew
1
@JohnThreepwood: classes, traits et objets. La plupart du temps, à Scala, le terme "classe" est utilisé pour désigner les classes, les traits et les objets. Ce n'est que lorsque l'on parle des différences spécifiques entre eux que cela signifie uniquement les classes. Le SLS utilise le terme «modèle» pour faire référence à la fois aux classes et aux traits, mais ce terme n'est pas beaucoup utilisé en dehors du SLS, et il n'y a pas de terme qui englobe les trois classes, traits et objets.
Jörg W Mittag
30

Je ressens également le besoin de vous indiquer les spécifications:

Le modificateur scellé s'applique aux dé fi nitions de classe. Une classe scellée ne peut pas être directement héritée, sauf si le modèle d'héritage est dé fi ni dans le même fichier source que la classe héritée. Cependant, les sous-classes d'une classe scellée peuvent être héritées n'importe où.

- M. Odersky. La spécification du langage Scala, version 2.8. en ligne, sept. 2013.

À
la source
7

brièvement:

  • Les traits scellés ne peuvent être étendus que dans le même fichier
  • Cette liste permet au compilateur de connaître facilement tous les sous-types possibles
  • Utilisez des traits scellés lorsque le nombre de sous-types possibles est fini et connu à l'avance
  • Une façon de créer quelque chose comme enum en Java
  • Aide à la définition des types de données algébriques (ADT)

et pour plus de détails Tout sur les traits scellés dans Scala

Majid Hosseini
la source