Frage

Mit Scala Befehlszeilen REPL:

def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}

gibt

error: type mismatch;
found: Int(2)
required: String

Es scheint, dass Sie nicht rekursive Methoden in der REPL überlastet definieren. Ich dachte, dies ein Fehler in dem Scala REPL war und reichte es, aber es war fast sofort mit „wontfix geschlossen: Ich sehe keine Möglichkeit, dies die Semantik des Dolmetschers unterstützt werden könnte, weil diese beiden Methoden müssen kompiliert werden zusammen." Er empfahl, die Methoden in einem einschließenden Objekt setzen.

Gibt es eine JVM Sprachimplementierung oder Scala-Experten, warum erklären könnte? Ich sehe, kann es ein Problem sein würde, wenn die Methoden sich zum Beispiel genannt, aber in diesem Fall?

oder ob dies eine zu große Frage und Sie glaube, ich brauche mehr Vorwissen, hat jemand irgendwelche gute Anbindung an Bücher oder Websites über Sprachimplementierungen, vor allem auf der JVM? (Ich weiß, über John Rose Blog, und das Buch Programming Language Pragmatik ... aber das ist es.)

War es hilfreich?

Lösung

Das Problem auf die Tatsache zurückzuführen ist, dass der Dolmetscher am häufigsten muss ersetzen vorhandene Elemente mit einem bestimmten Namen, anstatt sie zu überlasten. Zum Beispiel werde ich oft durch das Experimentieren mit etwas laufen, oft einer Methode namens test erstellen:

def test(x: Int) = x + x

Ein wenig später, lassen Sie sich sagen, dass ich bin mit einem andere Experiment und ich erstellen Sie eine andere Methode namens test, in keiner Zusammenhang mit dem ersten:

def test(ls: List[Int]) = (0 /: ls) { _ + _ }

Dies ist kein völlig unrealistisches Szenario. In der Tat ist es genau wie die meisten Menschen den Interpreter verwenden, oft ohne es zu merken. Wenn der Dolmetscher entschieden willkürlich beide Versionen von test in Rahmen zu halten, die zu verwirrend semantische Unterschiede bei der Verwendung Test führen könnte. Zum Beispiel könnten wir einen Anruf test, versehentlich machen eine Int vorbei anstatt List[Int] (nicht der unwahrscheinlichsten Unfall in der Welt):

test(1 :: Nil)  // => 1
test(2)         // => 4  (expecting 2)

Im Laufe der Zeit der Stammbereich des Interpreters würde mit verschiedenen Versionen von Methoden unglaublich vollgestopft bekommen, Feldern, etc. Ich neige dazu, meine Dolmetscherin für Tage zu einer Zeit offen zu lassen, aber wenn wie diese Überlastung erlaubt wäre, würden wir sein jeder so oft wie die Dinge zu „spülen“, um den Dolmetscher gezwungen bekamen zu verwirrend sein.

Es ist nicht eine Beschränkung der JVM oder die Scala-Compiler, es ist eine bewusste Design-Entscheidung. Wie im Bug erwähnt, können Sie immer noch, wenn Sie in etwas anderes sind überlastet als Stammbereich. Umschließenden Ihre Testmethoden innerhalb einer Klasse scheint die beste Lösung für mich.

Andere Tipps

% scala28
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def foo(x: Int): Unit = () ; def foo(x: String): Unit = { println(foo(2)) } 
foo: (x: String)Unit <and> (x: Int)Unit
foo: (x: String)Unit <and> (x: Int)Unit

scala> foo(5)

scala> foo("abc")
()

REPL akzeptieren, wenn Sie beiden Zeilen kopieren und einfügen, beide zur gleichen Zeit.

Wie von extempore der Antwort, es möglich ist, zu überlasten. Daniels Kommentar über Design-Entscheidung ist richtig, aber ich denke, unvollständig und ein wenig irreführend. Es gibt keine Ächtung von Überlastungen (da sie möglich sind), aber sie sind nicht leicht zu erreichen.

Die Design-Entscheidungen, die dazu führen, sind:

  1. Alle bisherigen Definitionen müssen vorhanden sein.
  2. Nur neu eingegebene Code kompiliert wird, anstatt alles neu zu kompilieren immer jedes Mal eingegeben werden.
  3. Es muss möglich sein, Definitionen neu zu definieren (wie Daniel erwähnt).
  4. Es muss möglich sein, Mitglieder zu definieren, wie vals und defs, nicht nur Klassen und Objekte.

Das Problem ist ... wie all diese Ziele zu erreichen? Wie verarbeiten wir Ihr Beispiel?

def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}

Beginnend mit dem vierten Element, A val oder def kann nur innerhalb eines class, trait, object oder package object definiert werden. So legt REPL die Definitionen innerhalb Objekte, wie folgt aus ( nicht unbedingt der Darstellung! )

package $line1 { // input line
  object $read { // what was read
    object $iw { // definitions
      def foo(x: Int): Unit = {}
    }
    // val res1 would be here somewhere if this was an expression
  }
}

Nun, darauf zurückzuführen, wie JVM arbeitet, wenn Sie einer von ihnen definiert sind, können Sie sie nicht verlängern. Sie könnten natürlich neu kompilieren alles, aber wir verworfen, dass. So müssen Sie es an einem anderen Ort Ort:

package $line1 { // input line
  object $read { // what was read
    object $iw { // definitions
      def foo(x: String): Unit = { println(foo(2)) }
    }
  }
}

Und dies erklärt, warum Ihre Beispiele sind nicht Überlastungen: sie an zwei verschiedenen Stellen definiert sind. Wenn Sie sie in der gleichen Zeile setzen, würden sie alle zusammen definiert werden, was sie Überlastungen machen würde, wie in extempore dem Beispiel gezeigt.

Wie bei den anderen Design-Entscheidungen, die jeweils neue Paket Importdefinitionen und „res“ aus früheren Paketen und die Importe können sie Schatten, was es möglich machen Sachen „neu zu definieren“.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top