53 votes

Quelle est la différence entre une classe et un type en Scala (et en Java) ?

Scala

Où peut-on observer des différences entre une classe et un type en Scala et pourquoi cette distinction est-elle importante ?

S'agit-il d'une considération uniquement du point de vue de la conception du langage ou a-t-elle un impact "pratique" lors de la programmation de Scala ?

Ou est-il fondamental de "sécuriser les frontières" du système de types ( Nothing , Null me viennent à l'esprit) ?

Java

Combien de considérations/différences/problèmes mentionnés ci-dessus peuvent également être reconnus en Java ?


(Voir Quelle est la différence entre Type et Classe ? comme une introduction agnostique à la langue).

44voto

James Iry Points 14192

Quand vous dites "type", je vais supposer que vous voulez surtout parler de type statique. Mais je parlerai bientôt des types dynamiques.

Un type statique est une propriété d'une partie d'un programme qui peut être prouvée de manière statique (statique signifie "sans l'exécuter"). Dans un langage à typage statique, chaque expression a un type, que vous l'écriviez ou non. Par exemple, dans le Cish "int x = a * b + c - d", a,b,c,et d ont des types, a * b a un type, a * b + c a un type et a * b + c -d a un type. Mais nous avons seulement annoté x avec un type. Dans d'autres langages, tels que Scala, C#, Haskell, SML et F#, même cela ne serait pas nécessaire.

Les propriétés qui peuvent être prouvées dépendent du vérificateur de type.

Une classe de style Scala, par contre, est juste la spécification d'un ensemble d'objets. Cette spécification comprend quelques informations de type et inclut de nombreux détails d'implémentation et de représentation tels que les corps de méthodes et les champs privés, etc. En Scala, une classe spécifie également certaines limites de modules.

De nombreux langages ont des types mais pas de classes et de nombreux langages ont des classes mais pas de types (statiques).

Il existe plusieurs différences observables entre les types et les classes. List[String] est un type mais pas une classe. En Scala, List est une classe mais normalement pas un type (il s'agit en fait d'un type supérieur). En C#, List n'est pas un type et en Java, c'est un "type brut".

Scala propose des types structurels. {def foo : Bar} désigne tout objet qui possède de manière prouvable une méthode foo qui renvoie un Bar, quelle que soit sa classe. C'est un type, mais pas une classe.

Les types peuvent être abstraits à l'aide de paramètres de type. Lorsque vous écrivez def foo[T](x : T) = ..., alors dans le corps de foo T est un type. Mais T n'est pas une classe.

Les types peuvent être virtuels en Scala (c'est-à-dire les "membres de type abstrait"), mais les classes ne peuvent pas être virtuelles avec Scala aujourd'hui (bien qu'il y ait une manière lourde de coder les classes virtuelles). https://wiki.scala-lang.org/display/SIW/VirtualClassesDesign )

Maintenant, les types dynamiques. Les types dynamiques sont des propriétés d'objets que le runtime vérifie automatiquement avant d'effectuer certaines opérations. Dans les langages OO basés sur des classes et typés dynamiquement, il existe une forte corrélation entre les types et les classes. La même chose se produit dans les langages JVM tels que Scala et Java, dont les opérations ne peuvent être vérifiées que dynamiquement, comme la réflexion et le casting. Dans ces langages, l'"effacement de type" signifie plus ou moins que le type dynamique de la plupart des objets est le même que celui de leur classe. Plus ou moins. Ce n'est pas le cas, par exemple, des tableaux qui ne sont pas typiquement effacés pour que le runtime puisse faire la différence entre Array[Int] et Array[String]. Mais rappelez-vous ma définition large "les types dynamiques sont des propriétés d'objets que le runtime vérifie automatiquement". Lorsque vous utilisez la réflexion, il est possible d'envoyer n'importe quel message à n'importe quel objet. Si l'objet supporte ce message, tout fonctionne. Il est donc logique de parler de tous les objets qui peuvent faire coin-coin comme un canard comme d'un type dynamique, même si ce n'est pas une classe. C'est l'essence même de ce que les communautés Python et Ruby appellent le "duck typing". De même, selon ma définition large, même "zeroness" est un type dynamique dans le sens où, dans la plupart des langages, le runtime vérifie automatiquement les nombres pour s'assurer que vous ne divisez pas par zéro. Il y a très, très peu de langages qui peuvent le prouver de manière statique en faisant de zéro (ou non zéro) un type statique.

Enfin, comme d'autres l'ont mentionné, il y a des types comme int qui n'ont pas de classe comme détail d'implémentation, des types comme Null et Any qui sont un peu spéciaux mais qui pourraient avoir des classes et n'en ont pas, et des types comme Nothing qui n'a même pas de valeurs et encore moins de classe.

24voto

Kevin Wright Points 31665

Ok, je vais mordre... James a une bonne réponse, alors je vais essayer un tact différent et donner un point de vue plus terre à terre.

De manière générale, une classe est quelque chose qui peut être instancié . les objets singletons (Scala), les traits (Scala) et les interfaces (Scala) sont aussi généralement considérés comme des classes. Cela est logique, car les singletons sont toujours instanciés (via le code généré par le compilateur) et une interface peut être instanciée dans le cadre d'une sous-classe.

Ce qui nous amène au deuxième point. Les classes sont l'unité primaire de conception dans la plupart des langages orientés objet (mais pas dans les langages basés sur des prototypes comme javascript). Le polymorphisme et le sous-classement sont tous deux définis en termes de classes. Les classes fournissent également un espace de noms et des contrôles de visibilité.


Les types sont une chose très différente, chaque valeur possible que le système peut exprimer aura un ou plusieurs types, et ceux-ci peuvent parfois être assimilés à des classes, par exemple :

(Int) => String // both the type and class are Function1[Int,String]
"hello world" // class and type are String    

Vous obtenez également des différences intéressantes entre Scala et Java :

7 // both the class and type are Int in Scala
  // in Java there's no class and the type is Integer.TYPE

println("hello world") // the return type is Unit, of class Unit
                       // Java has void as a type, but no corresponding class

error("oops") // the type and class are both "Nothing"

et les types vraiment amusants qui ne sont pas des classes du tout. Par exemple, this.type fait toujours référence au type unique de this . Il est unique à une seule instance et n'est même pas compatible avec les autres instances de la même classe.

Il existe également des types abstraits et des paramètres de type. Par exemple :

type A // 'A' is an undetermined abstract type
       // to be made concrete in a subclass

class Seq[T] { ... } // T is a type, but not a class

Seq est intéressant car il s'agit d'une classe, mais pas d'un type. Plus précisément, c'est un "constructeur de type" ; quelque chose qui construira un type valide lorsqu'on lui fournira le paramètre de type nécessaire. Un autre terme pour les constructeurs de type est "higher kinded types", personnellement je n'aime pas ce terme, car "constructeur de type" m'encourage à penser en termes de fourniture de types comme toute autre forme d'argument - un modèle mental qui m'a bien servi pour Scala.

"de nature supérieure" implique à juste titre que Seq a un "genre", qui est * => * cette notation indique que Seq prendra un seul type et donnera un seul type (ceci est similaire à la notation curée pour décrire les fonctions). À titre de comparaison, le type de Map est * => * => * car il prend deux paramètres de type.

3voto

Landei Points 30509

Un type peut être utile par lui-même, sans aucune instance. Un exemple de cela est appelé "type fantôme". Voici un exemple pour Java : http://michid.wordpress.com/2008/08/13/type-safe-builder-pattern-in-java/

Dans cet exemple, nous avons public static class Initializer<HA, HB> , donde HA y HB prennent certains types (représentés par les classes abstraites TRUE y FALSE ), sans jamais être instancié.

J'espère que cela montre que les types et les classes sont quelque chose de différent, et que les types peuvent être utiles par eux-mêmes.

1voto

irreputable Points 25577

(Java uniquement) Je dirais qu'un type est un ensemble d'objets. Objet o est le type X si o est un membre de l'ensemble X . Type X est un sous-type de Y si elle est fixée X est un sous-ensemble de Y .

Pour chaque classe C (pas d'interface), il existe un ensemble d'objets, créés à partir de new C(...) . Il est intéressant de noter que nous nous soucions rarement de cet ensemble. (mais chaque objet appartient à un ensemble comme celui-ci, un fait qui peut être utile)

Pour chaque classe C, il existe un type t(C) généralement appelé "le type C", qui est l'ensemble de tous les objets qui peuvent être créés à partir de new S(...) où S est C ou une sous-classe de C.

De même, pour chaque interface I, il existe un type t(I) le "type I", qui est l'ensemble de tous les objets qui peuvent être créés à partir de new S(...) où S met en œuvre I.

Évidemment, si la classe S est une sous-classe de C le type S est un sous-type du type C. Il en va de même pour l'interface I

Il existe un type nul, qui est l'ensemble vide. Le type nul est un sous-type de chaque type.

Il existe un ensemble de tous les objets, qui est le type Object. C'est un super type de chaque type.

Jusqu'à présent, ce formalisme est plutôt inutile. Un type est fondamentalement la même chose qu'une classe ou une interface, et la relation de sous-type est fondamentalement la relation sous-classe/sous-interface. La trivialité est une bonne chose, le langage était compréhensible ! Mais en entrant dans les génériques, il y a des types plus compliqués, et des opérations comme les unions et les intersections de types. Les types ne sont plus seulement des classes et des interfaces, et les relations de sous-type sont beaucoup plus riches et plus difficiles à comprendre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X