Plus ou moins toute utilisation de membre (ie. imbriquée) types peuvent donner lieu à un besoin de charge pour les types de méthode. En particulier, je maintiens que sans dépendant de la méthode des types de la classique le modèle de gâteau est plus près d'être un anti-modèle.
Quel est donc le problème? Les types imbriqués dans Scala sont dépendants de leur joignant instance. Par conséquent, en l'absence de dépendant de la méthode des types, des tentatives de les utiliser en dehors de cette instance peut être très difficile. Cela peut tourner à des conceptions qui, au départ, semblaient élégant et attrayant dans monstruosités qui sont nightmarishly rigide et difficile à refactoriser.
Je vais l'illustrer avec un exercice que je donne lors de mon Avancée Scala cours de formation,
trait ResourceManager {
type Resource <: BasicResource
trait BasicResource {
def hash : String
def duplicates(r : Resource) : Boolean
}
def create : Resource
// Test methods: exercise is to move them outside ResourceManager
def testHash(r : Resource) = assert(r.hash == "9e47088d")
def testDuplicates(r : Resource) = assert(r.duplicates(r))
}
trait FileManager extends ResourceManager {
type Resource <: File
trait File extends BasicResource {
def local : Boolean
}
override def create : Resource
}
class NetworkFileManager extends FileManager {
type Resource = RemoteFile
class RemoteFile extends File {
def local = false
def hash = "9e47088d"
def duplicates(r : Resource) = (local == r.local) && (hash == r.hash)
}
override def create : Resource = new RemoteFile
}
C'est un exemple classique de modèle de gâteau: nous avons une famille d'abstractions qui sont progressivement affinées par une hiérarchie (ResourceManager
/Resource
sont définies en FileManager
/File
qui sont à leur tour raffiné en NetworkFileManager
/RemoteFile
). C'est un jouet, par exemple, mais le modèle est réel: il est utilisé tout au long de la Scala compilateur et a été largement utilisé dans la Scala plugin Eclipse.
Voici un exemple de l'abstraction dans l'utilisation,
val nfm = new NetworkFileManager
val rf : nfm.Resource = nfm.create
nfm.testHash(rf)
nfm.testDuplicates(rf)
Notez que le chemin de la dépendance signifie que le compilateur va garantir que l' testHash
et testDuplicates
méthodes NetworkFileManager
ne peut être appelée avec des arguments qui lui correspondent, c'est à dire. c'est propre RemoteFiles
, et rien d'autre.
C'est indéniablement une propriété souhaitable, mais supposons que nous voulions déplacer ce test de code dans un autre fichier source? Ayant à charge les types de méthode c'est trivial à redéfinir ces méthodes à l'extérieur de l' ResourceManager
de la hiérarchie,
def testHash4(rm : ResourceManager)(r : rm.Resource) =
assert(r.hash == "9e47088d")
def testDuplicates4(rm : ResourceManager)(r : rm.Resource) =
assert(r.duplicates(r))
Remarque l'utilise charge les types de méthode ici: le type de la deuxième argument (rm.Resource
) dépend de la valeur du premier argument (rm
).
Il est possible de le faire sans dépendant de la méthode des types, mais il est extrêmement maladroit, et le mécanisme est assez peu intuitive: j'ai été l'enseignement de ce cours pendant près de deux ans maintenant, et depuis ce temps, personne n'est venu avec une solution de travail de manière spontanée.
Essayez par vous-même ...
// Reimplement the testHash and testDuplicates methods outside
// the ResourceManager hierarchy without using dependent method types
def testHash // TODO ...
def testDuplicates // TODO ...
testHash(rf)
testDuplicates(rf)
Après un court moment, en difficulté avec elle, vous découvrirez probablement pourquoi j'ai (ou c'était peut-être David MacIver, nous ne pouvons pas nous souvenir de qui nous a inventé le terme) appellent cela la Boulangerie de Doom.
Edit: le consensus est que la Boulangerie de Doom était David MacIver de la monnaie ...
Pour les bonus: Scala, à la forme de types de charge en général (et dépendant de la méthode des types comme une partie de celui-ci) a été inspiré par le langage de programmation Beta ... ils se posent tout naturellement dans la Bêta constante de la nidification de la sémantique. Je ne connais pas d'autre, même faiblement, intégrer langage de programmation qui a des types dépendants dans ce formulaire. Les langues, comme le Coq, le poivre de Cayenne, de l'Épigramme et Agda ont une forme différente de l'dépendante de frappe qui est d'une certaine façon plus générale, mais qui diffère de manière significative, en faisant partie de systèmes de type qui, contrairement à la Scala, de ne pas avoir de sous-typage.