2010-04-21 4 views
8

Dieser einfache Test, natürlich, wie erwartet funktioniert:Scala räumt der impliziten Konvertierung Vorrang vor "natürlichen" Operationen ein ... Warum? Ist das ein Fehler? Oder mache ich etwas falsch?

 
scala> var b = 2 
b: Int = 2 

scala> b += 1 

scala> b 
res3: Int = 3 

Nun ist diese in Umfang Ich bringe:

 
class A(var x: Int) { def +=(y:Int) { this.x += y } } 
implicit def int2A(i:Int) : A = new A(i)    

Ich bin eine neue Klasse definiert und einen + = Betrieb auf, und eine bequeme implizite Konvertierung für die Zeiten, wenn ich Int Int Int einen Int-Wert hinzufügen möchte.

Ich hätte nie erwartet, dass dies die Art beeinflussen würde, wie sich meine regulären Int-Operationen verhalten, wenn die Klasse "A" überhaupt nicht Teil des Ausdrucks ist.

Aber es tut:

 
scala> var b:Int = 0 
b: Int = 0 

scala> b += 1 

scala> b 
res29: Int = 0 

scala> b += 2 

scala> b 
res31: Int = 0 

Was hier zu sein scheint passiert ist, dass die b: Int implizit zu einem „A“ umgewandelt, die nicht an eine Variable gebunden ist, und dann + = aufgerufen wird darauf, die Ergebnisse verwerfen.

Scala scheint der impliziten Umwandlung gegenüber dem natürlichen + = - Verhalten (Compiler-Magie, keine tatsächliche Methode), die bereits für Ints definiert ist, eine hohe Priorität zu geben. Common-sense sowie ein C++ - Hintergrund sagt mir, dass implicits nur als letzter Ausweg aufgerufen werden sollte, wenn die Kompilierung sonst fehlschlagen würde. Das führt zu mehreren Fragen ...

  • Warum? Ist das ein Fehler? Ist es von Entwurf?
  • Gibt es einen Workaround (außer nicht mit "+ =" für meine DSL "+ =" Operation)?

Dank

+0

'scala -Xprint: typer' sagt mir, dass es genau das tut, was Sie sagten, es tut - mit einer impliziten Umwandlung, so dass es' + = 'aufrufen konnte. –

Antwort

1

Sogar Eastsun's Erklärung zu widerstehen, es scheint, als ob dies ein Fehler ist, und es sollte die b=b+1 Transformation versuchen, bevor Sie eine implizite Konvertierung für += versuchen.

Diese Frage können Sie per E-Mail an [email protected] oder per E-Mail an n4.nabble.com/Scala-User-f1934582.html stellen. Wenn es ein Fehler ist, wird es bemerkt und behoben.

+0

Danke ... Scala Bug # 3377 –

+0

https://github.com/scala/bug/issues/3377 –

3

Ich glaube nicht, dass es ein Fehler ist. Tatsächlich hat Int nur eine "+" - Methode, aber keine "+ =" -Methode. b + = 1 würde sich in der Kompilierzeit in b = b + 1 umwandeln, wenn es kein anderes implizites Objekt gibt, für das eine "+ =" -Methode existiert.

+0

Ich denke, selbst wenn du deiner Erklärung widerstehst, ist es wahrscheinlich ein Fehler, und es sollte die Umwandlung versuchen, bevor du eine implizite Konvertierung für + = –

6

von der Programmierung in Scala, Kapitel 17:

Jedes Mal, wenn Sie schreiben, a + = b und a tut eine Methode nicht genannt + =, Scala werden versuchen, es als eine Interpretation = a + b .

Die Klasse Int enthält keine Methode +=. Die Klasse A bietet jedoch die Methode +=. Dies könnte die implizite Konvertierung von Int zu A auslösen.

+0

dankest. Ich bin sehr enttäuscht von der Menge an "Magie", die in einer "sehr orthogonalen, sauberen Sprache" implementiert wurde. Sie sollten einfach + = in Int implementieren und die Compiler-Magie loswerden. Ich hoffe, dass es eine Scala 3.0 geben wird :) –

+3

@Alex Wie würdest du '+ =' auf einer unveränderlichen Klasse implementieren? –

+1

@Ben: +1, Guter Punkt. – missingfaktor

1

Scala scheint hohe Priorität die implizite Konvertierung über die natürliche += zu geben, die bereits zu Int s definiert ist.

Über welche Version von Scala sprechen Sie? Ich kenne keine Version, die eine += Methode auf Int hat. Sicher, keine der noch unterstützten Versionen tun, das muss einige wirklich alte Version, die Sie dort haben.

Und da es keine += auf Int ist, aber Sie sind eine += Methode auf Int Aufruf versucht Scala diese Art Zwang über eine implizite Konvertierung zu befriedigen.

+0

Bearbeitete meine Frage zu klären Int. + = Ist Compiler Magie, keine tatsächliche Methode. –

13

Wie andere bemerkt haben, kann Int keine + = "Methode" haben, weil Int unveränderlich ist. Was stattdessen passiert, ist, dass x + = 1 als Kurzform für x = x + 1 behandelt wird, aber nur, wenn es keine Methode namens + = gibt, die für den Typ definiert ist. Daher hat die Methodenauflösung Vorrang.

Da Scala erlaubt, + = Methoden zu definieren und + + auf Variablen zu setzen, hätten wir die Priorität der beiden ändern können? I.e. versuche expanded + = first und nur wenn das fehlschlägt suche nach einer Methode namens + =?

Theoretisch ja, aber ich argumentiere, es wäre schlimmer gewesen als das aktuelle Schema. Praktisch, nein. Es gibt viele Arten in der Sammlungsbibliothek von Scala, die sowohl eine + -Methode für die nicht-destruktive Addition als auch eine + = Methode für die destruktive Addition definieren. Wenn wir die Priorität vertauscht hatten dann einen Anruf wie

 
    myHashTable += elem 

würde erweitern

 
    myHashTable = myHashTable + elem 

So würde es eine neue Hash-Tabelle konstruieren und diese zurück in dem Variablen zuweisen, anstatt einfach ein Element zu aktualisieren. Keine weise Sache zu tun ...

+1

Aber könnten wir nicht versuchen, myHashTables '+ = 'auszuführen, und dann, wenn wir sehen, dass es nicht gefunden wird, erweitern wir es auf' myHashTable = myHashTable + elem', und fällt dies nicht auf implizite Konvertierungen zurück? –

+1

Dies würde die Dinge noch komplizierter machen. Und es würde eine Klasse nützlicher Refactorings ungültig machen, bei denen Vererbung durch Ansichten ersetzt wird. –

+0

Ich stimme zu, dass der Versuch, eine + = -Methode vor der Erweiterung auf "... = ... + ..." zu finden, durchaus Sinn ergibt. Was ich nicht stimme, ist eine implizite Umwandlung zu erzwingen, nur um ein + = in einer Klasse zu finden, die mit dem vorliegenden Ausdruck "nicht verwandt" ist. Ein anderer Ansatz bestünde darin, + = in Int formell zu definieren, so dass es früher (vor der impliziten Konvertierung) "gefunden" wird, aber eine spezielle Syntax verwendet, um darauf hinzuweisen, dass es "keine echte Methode" ist . BTW Ich bin geschmeichelt, um eine Antwort direkt von oben zu bekommen :) Danke –

Verwandte Themen