Je fais des recherches sur le langage de programmation de la conception, et je me suis intéressé à la question de comment faire pour remplacer le populaire répartition unique de transmission de message OO paradigme avec l'multimethods générique-fonction de paradigme. Pour la plupart, il semble très simple, mais j'ai récemment devenu coincé et apprécierait un peu d'aide.
De passage de Message OO, dans mon esprit, est une solution qui permet de résoudre deux différents problèmes. J'explique ce que je veux dire en détail dans le pseudo-code suivant.
(1) Il résout le problème de répartition:
=== dans le fichier de l'animal.code ===
- Animals can "bark"
- Dogs "bark" by printing "woof" to the screen.
- Cats "bark" by printing "meow" to the screen.
=== dans le fichier myprogram.code ===
import animal.code
for each animal a in list-of-animals :
a.bark()
Dans ce problème, "écorce" est une méthode avec plusieurs "branches" qui fonctionnent différemment selon les types d'argument. Nous mettons en œuvre "écorce" une fois pour chaque type d'argument qui nous intéresse (Chiens et Chats). Au moment de l'exécution, nous sommes en mesure de parcourir une liste d'animaux et de sélectionner de façon dynamique la branche appropriée à prendre.
(2) Il résout le problème de l'espace de noms:
=== dans le fichier de l'animal.code ===
- Animals can "bark"
=== dans l'arborescence des fichiers.code ===
- Trees have "bark"
=== dans le fichier myprogram.code ===
import animal.code
import tree.code
a = new-dog()
a.bark() //Make the dog bark
…
t = new-tree()
b = t.bark() //Retrieve the bark from the tree
Dans ce problème, "écorce" est en fait deux conceptuellement différentes fonctions qui vient d' arriver à avoir le même nom. Le type de l'argument (que ce soit chien ou d'un arbre) détermine la fonction que nous réellement dire.
Multimethods élégante de résoudre le problème numéro 1. Mais je ne comprends pas comment ils résolvent le problème numéro 2. Par exemple, le premier des deux exemples ci-dessus peut être traduit en un simple mode de multimethods:
(1) les Chiens et les Chats à l'aide de multimethods
=== dans le fichier de l'animal.code ===
- define generic function bark(Animal a)
- define method bark(Dog d) : print("woof")
- define method bark(Cat c) : print("meow")
=== dans le fichier myprogram.code ===
import animal.code
for each animal a in list-of-animals :
bark(a)
Le point clé est que la méthode de l'écorce(le Chien) est conceptuellement liées à l'écorce(Cat). Le deuxième exemple n'a pas cet attribut, c'est pourquoi je ne comprends pas comment multimethods résoudre la question de l'espace de noms.
(2) Pourquoi multimethods ne travaille pas pour les Animaux et les Arbres
=== dans le fichier de l'animal.code ===
- define generic function bark(Animal a)
=== dans l'arborescence des fichiers.code ===
- define generic function bark(Tree t)
=== dans le fichier myprogram.code ===
import animal.code
import tree.code
a = new-dog()
bark(a) /// Which bark function are we calling?
t = new-tree
bark(t) /// Which bark function are we calling?
Dans ce cas, où la fonction générique-elles être définies? Devrait-il être défini au niveau supérieur, au-dessus à la fois des animaux et des arbres? Il n'a pas de sens de parler de l'écorce pour en faire des animaux et des arbres comme les deux méthodes de la même fonction générique parce que les deux fonctions sont conceptuellement différentes.
Autant que je sache, je n'ai pas trouvé de travail dans le passé qui a résolu ce problème. J'ai regardé Clojure multimethods, et le CLOS multimethods et ils ont le même problème. Je suis en croisant les doigts et en espérant une solution élégante au problème, ou de persuader les arguments sur pourquoi c'est pas vraiment un problème dans la vraie programmation.
S'il vous plaît laissez-moi savoir si la question a besoin de clarification. C'est une assez subtile (mais important) point je pense.
Merci pour les réponses à la santé mentale, Rainer, Marcin, et Matthias. Je comprends vos réponses et tout à fait d'accord que la distribution dynamique et résolution d'espace de noms sont deux choses différentes. CLOS ne fait pas l'amalgame entre les deux idées, alors que le traditionnel passage de message OO n'. Cela permet également une extension de multimethods à l'héritage multiple.
Ma question est spécifiquement dans la situation où l'amalgame est souhaitable.
L'exemple suivant est un exemple de ce que je veux dire.
=== le fichier XYZ.code ===
define class XYZ :
define get-x ()
define get-y ()
define get-z ()
=== fichier: POINT.code ===
define class POINT :
define get-x ()
define get-y ()
=== fichier: GÈNE.code ===
define class GENE :
define get-x ()
define get-xx ()
define get-y ()
define get-xy ()
==== fichier: my_program.code ===
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
obj.get-x()
pt = new-point()
pt.get-x()
gene = new-point()
gene.get-x()
En raison de la conjonction de résolution d'espace de noms avec l'expédition, le programmeur peut naïvement appel de get-x() sur les trois objets. C'est également parfaitement univoque. Chaque objet possède son propre ensemble de méthodes, alors il n'y a pas de confusion quant à ce que le programmeur voulait dire.
Contraste avec l'multimethod version:
=== le fichier XYZ.code ===
define generic function get-x (XYZ)
define generic function get-y (XYZ)
define generic function get-z (XYZ)
=== fichier: POINT.code ===
define generic function get-x (POINT)
define generic function get-y (POINT)
=== fichier: GÈNE.code ===
define generic function get-x (GENE)
define generic function get-xx (GENE)
define generic function get-y (GENE)
define generic function get-xy (GENE)
==== fichier: my_program.code ===
import XYZ.code
import POINT.code
import GENE.code
obj = new-xyz()
XYZ:get-x(obj)
pt = new-point()
POINT:get-x(pt)
gene = new-point()
GENE:get-x(gene)
Parce que get-x() de XYZ n'a pas conceptuel rapport à x() de GÈNES, ils sont mis en œuvre en tant que distincte des fonctions génériques. Par conséquent, la fin programmeur (en my_program.code) doit explicitement qualifier get-x() et dire le système qui get-x() il veut dire, en fait appel.
Il est vrai que cette approche explicite est plus clair et facilement généralisable à de multiples expédition et de l'héritage multiple. Mais à l'aide de (abuser) d'expédition pour résoudre les problèmes d'espace de noms est une option extrêmement utile de passage de message OO.
Personnellement, je pense que 98% de mon propre code est suffisamment exprimé à l'aide de répartition unique et unique héritage. J'utilise cette commodité d'utilisation de l'expédition pour la résolution d'espace de noms bien plus que ce que j'multiples pour l'expédition, de sorte que je suis réticent à l'abandonner.
Est-il possible de me faire le meilleur des deux mondes? Comment puis-je éviter la nécessité de qualifier explicitement mes appels de fonction dans un multi-paramètre de méthode?
Il semble que le consensus est que les
- multimethods résoudre l'envoi problème, mais n'attaque pas le problème de l'espace de noms.
- les fonctions qui sont conceptuellement différents doivent avoir des noms différents, et les utilisateurs devraient être devraient manuellement les qualifier.
Ensuite, je crois que, dans les cas où seul l'héritage de répartition unique est suffisante, de passage de message OO est plus pratique que les fonctions génériques.
Cela sonne comme il est ouvert de recherche. Si une langue à fournir un mécanisme pour multimethods qui peut également être utilisé pour la résolution d'espace de noms, ce serait une fonction souhaitée?
J'aime le concept de fonctions génériques, mais se sentent actuellement ils sont optimisés pour faire "des choses très dures pas si dur" au détriment de "faire les choses triviales légèrement ennuyeux". Étant donné que la majorité du code est trivial, je crois toujours que c'est un bon problème à résoudre.