it-swarm.com.de

Wie vermeiden Merkmale in Scala den "Diamantfehler"?

(Hinweis: Ich habe aus offensichtlichen Gründen 'Fehler' anstelle von 'Problem' im Titel verwendet ..;)).

Ich habe einige grundlegende Lektüre über Eigenschaften in Scala gemacht. Sie ähneln Interfaces in Java oder C #, erlauben jedoch die Standardimplementierung einer Methode.

Ich habe mich gefragt: Kann dies nicht zu einem Fall des "Diamantproblems" führen, weshalb viele Sprachen die Mehrfachvererbung überhaupt vermeiden?

Wenn ja, wie geht Scala damit um?

16
Aviv Cohn

Das Diamantproblem ist die Unfähigkeit zu entscheiden, welche Implementierung der Methode gewählt werden soll. Scala löst dieses Problem, indem definiert wird, welche Implementierung als Teil der Sprachspezifikationen ausgewählt werden soll ( lesen Sie den Teil über Scala in diesem Wikipedia-Artikel ).

Natürlich könnte dieselbe Ordnungsdefinition auch bei der Mehrfachvererbung von Klassen verwendet werden. Warum also mit Merkmalen arbeiten?

Der Grund, warum IMO Konstruktoren sind. Konstruktoren haben mehrere Einschränkungen, die reguläre Methoden nicht haben - sie können nur einmal pro Objekt aufgerufen werden, sie müssen für jedes neue Objekt aufgerufen werden, und der Konstruktor einer untergeordneten Klasse muss den Konstruktor des übergeordneten Elements als erste Anweisung aufrufen (die meisten Sprachen werden dies tun) Tun Sie dies implizit für Sie, wenn Sie keine Parameter übergeben müssen.

Wenn B und C A und D erben und B und C erben und die Konstruktoren von B und C den Konstruktor von A aufrufen, ruft der Konstruktor von D den Konstruktor von A zweimal auf. Das Definieren der zu wählenden Implementierungen wie Scala hat mit Methoden gearbeitet) funktioniert hier nicht, da sowohl B- als auch C-Konstruktoren sein müssen namens.

Merkmale vermeiden dieses Problem, da sie keine Konstruktoren haben.

22
Idan Arye

Scala vermeidet das Diamantproblem durch etwas, das als "Merkmalslinearisierung" bezeichnet wird. Grundsätzlich wird die Methodenimplementierung in den Merkmalen nachgeschlagen, die Sie von rechts nach links erweitern. Einfaches Beispiel:

trait Base {
   def op: String
}

trait Foo extends Base {
   override def op = "foo"
}

trait Bar extends Base {
   override def op = "bar"
}

class A extends Foo with Bar
class B extends Bar with Foo

(new A).op
// res0: String = bar

(new B).op
// res1: String = foo

Allerdings enthält die Liste der Merkmale, nach denen gesucht wird, möglicherweise mehr als die von Ihnen explizit angegebenen, da sie möglicherweise andere Merkmale erweitern. Eine ausführliche Erklärung finden Sie hier: Merkmale als stapelbare Modifikationen und ein vollständigeres Beispiel für die Linearisierung hier: Warum nicht Mehrfachvererbung?

Ich glaube, in anderen Programmiersprachen wird dieses Verhalten manchmal als "Method Resolution Order" oder "MRO" bezeichnet.

21
lutzh