J'ai vu beaucoup de gens dans la communauté Scala conseiller d'éviter de sous-typer "comme une peste". Quelles sont les différentes raisons contre l'utilisation du sous-typage? Quelles sont les alternatives?
Réponses
Trop de publicités?Types de déterminer la granularité de la composition, c'est à dire de l'extensibilité.
Par exemple, une interface, par exemple Comparable, qui combine (donc de l'amalgame) l'égalité et les opérateurs relationnels. Ainsi, il est impossible de composer sur un seul de l'égalité ou relationnelle de l'interface.
En général, le principe de substitution de l'héritage est indécidable. Russell paradoxe implique que tout jeu qui est extensible (c'est à dire ne pas énumérer le type de chaque membre ou d'un sous-type), peuvent inclure lui-même, c'est à dire un sous-type de lui-même. Mais dans le but d'identifier (décider) ce qu'est un sous-type, et non lui-même, les invariants de lui-même doit être complètement énumérés, ainsi il n'est plus extensible. C'est le paradoxe qui sous-typés extensibilité du fait de l'héritage indécidable. Ce paradoxe doit exister, sinon de la connaissance qui serait statique et donc de la connaissance de la formation n'existerait pas.
Fonction de la composition est surjective substitution de sous-typage, parce que l'entrée d'une fonction peut être substitué à sa sortie, c'est à dire n'importe où sur le type de sortie est prévu, le type d'entrée peut être substitué, en l'enveloppant dans l'appel de fonction. Mais la composition ne fait pas de l'bijective contrat de sous-typage-- accéder à l'interface de la sortie d'une fonction, n'a pas accès à l'entrée de l'instance de la fonction.
Donc la composition n'a pas à maintenir à l' avenir (c'est à dire illimité) les invariants et peut donc être à la fois extensible et decidable. Le sous-typage peut être BEAUCOUP plus puissant lorsqu'il est prouvable decidable, car il maintient cette bijective contrat, par exemple une fonction qui trie une liste immuable de la supertype, peut fonctionner sur la liste immuable du sous-type.
Donc la conclusion est d'énumérer tous les invariants de chaque type (c'est à dire de ses interfaces), à faire de ces types orthogonale (optimiser la granularité de la composition), puis d'utiliser la fonction de composition pour accomplir l'extension où ces invariants ne serait pas orthogonaux. Ainsi, un sous-type est approprié seulement où il est prouvable modèles les invariants de la supertype de l'interface, et l'interface supplémentaire(s) du sous-type sont sensiblement orthogonale à la invariants de l'supertype de l'interface. Ainsi, les invariants de l'interface doit être orthogonale.
Catégorie de la théorie prévoit des règles pour le modèle des invariants de chaque sous-type, c'est à dire de Foncteur, Applicative, et la Monade, qui préservent la fonction de la composition sur la levée de types, c'est à dire voir l'exemple précité de la puissance de sous-typage pour les listes.
Une des raisons est que equals () est très difficile à obtenir correctement lorsque le sous-typage est impliqué. Voir Comment écrire une méthode d'égalité en Java . Plus précisément "Piège n ° 4: ne pas définir égaux comme une relation d'équivalence". En substance: pour obtenir une égalité correcte sous-typage, vous avez besoin d'une double dépêche.
Je pense que le contexte général est celui de la lanaguage d'être aussi "pure" que possible (c'est à dire en utilisant autant que possible les fonctions pures), et vient de la comparaison avec Haskell.
À partir "les Ruminations d'un Programmeur"
Scala, étant un hybride OO-FP langue a à s'occuper de questions comme le sous-typage (qui Haskell n'a pas).
Comme mentionné dans ce PSE réponse:
aucun moyen de restreindre à un sous-type de sorte qu'il ne peut pas faire plus que le type dont il hérite.
Par exemple, si la classe de base est immuable et définit un pur méthodefoo(...)
, les classes dérivées doivent pas être mutables ou remplacerfoo()
avec une fonction qui n'est pas pur
Mais, pour que la recommandation serait d'utiliser la meilleure solution adaptée pour le programme que vous êtes en train de développer.
En se concentrant sur le sous-typage, en ignorant les questions liées à la les classes, l'héritage, la programmation orientée objet, etc.. Nous avons l'idée de sous-typage représente un isa relation entre les types. Par exemple, les types A et B ont différentes opérations mais si Un isa B, on peut utiliser l'un quelconque de B opérations sur un A.
Otoh, que, en utilisant une autre relation traditionnelle, si C hasa B alors on peut réutiliser tout de B opérations sur un C. Généralement langues vous permettent d'écrire l'une avec une belle syntaxe, une.opOnB au lieu d'un.super.opOnB comme elle le serait dans le cas de la composition, de la c.b.opOnB
Le problème est que dans de nombreux cas, il n'y a plus d'une façon de lier deux types. Pour exemple Réel peut être intégré dans un Complexe en supposant que 0 sur la partie imaginaire, mais Complexe, qui peut être incorporé dans le Réel, en ignorant la partie imaginaire, qui peuvent donc être considérés comme des sous-types de l'autre et le sous-typage des forces un rapport à être considérées comme privilégiées. Aussi, il y a plus de relations possibles (par exemple, afficher Complexe comme un Réel à l'aide de thêta composante de la représentation polaire).
Dans la terminologie officielle nous avons l'habitude de dire morphism à de telles relations entre types et y sont des types spéciaux de morphisms pour les relations avec les différentes propriétés (par exemple un isomorphisme, homomorphism).
Dans une langue de sous-typage habituellement, il y a beaucoup plus de sucre sur isa relations et donné de nombreuses possibilités d'incorporations nous avons tendance à voir des frictions inutiles chaque fois que nous sommes à l'aide de la unpreferred relation. Si nous apportons de l'héritage, les classes et la programmation orientée objet-les au mélange, le problème devient beaucoup plus visible et de désordre.
Je ne connais pas Scala, mais je pense que le mantra "préférer la composition à l'héritage" s'applique à Scala exactement comme il le fait pour tous les autres langages de programmation OO (le sous-typage est souvent utilisé avec le même sens que "héritage". Ici
Vous préférez la composition à l'héritage?
vous trouverez quelques informations supplémentaires.