Clojure überladene Methodenauflösung für Longs

8

Dieses Verhalten ergibt für mich keinen Sinn:

%Vor%

Warum findet der (BigDecimal. (Long. 1)) -Fall keine eindeutige übereinstimmende Methodensignatur, während die anderen beiden Ausdrücke - die genau den gleichen Argumenttyp haben - erfolgreich sind?

Aktualisierung:

Was ich an diesem Verhalten sogar mehr seltsam finde, ist, dass es dem Long -Typ besonders ähnelt:

%Vor%     
DaoWen 25.09.2012, 16:08
quelle

2 Antworten

11

Aus dieser Diskussion in der Clojure-Diskussionsgruppe scheint es, als wären Sie schon einmal begegnet eine Designentscheidung von Rich Hickey. Da BigDecimal keinen Konstruktor der Signatur BigDecimal(Long long) (Edit: ) hat und der Compiler daher zwischen den Konstruktoren int und long wählen muss, lesen Sie die Kommentare unten Warum verwendet Integer ), wird der Compiler nicht versuchen, zu "erraten", welcher Konstruktor gemeint ist, und explizit fehlschlägt.

  

Die Quintessenz ist, dass bestimmte Typanforderungen auf der Java-Seite explizites Boxen erfordern, um korrekten und nicht spröden Code zu haben. - Rich Hickey

Beachten Sie, dass Literale als Primitive, nicht als "Boxed" -Typen geparsed werden, pro diese Dokumentation :

  

Im Gegensatz zu früheren Versionen von Clojure werden numerische Literale als primitive Longs oder Doubles analysiert.

Um zu verstehen, warum die anderen Operationen funktionieren, müssen Sie in die Clojure-Quelle eintauchen, insbesondere Compiler.java und ihre innere Klasse NumberExpr . Das ist die Stelle, an der Ihr Literal automatisch in ein Long umgewandelt wird und der Compiler kein Problem hat, indem er Object.getClass() aufruft (was sowohl type als auch class tun).

In der Compiler.getMatchingParams() versucht der Clojure-Compiler, den zu verwendenden Konstruktor von BigDecimal aufzulösen. Sie haben jedoch explizit angegeben, dass Ihr Parameter den Typ Long hat - es gibt keinen Konstruktor für BigDecimal, der diesen Typ verwendet.

Vielleicht ist das kein "gesunder Menschenverstand", aber Rich Hickey hat die Entscheidung getroffen, dass Sie genau über den Typ Ihrer Parameter Bescheid wissen müssen und dass sie dem Typ der Java-Klasse entsprechen müssen. Der Compiler weigert sich, Ihre Absicht zu erraten.

Beachten Sie Folgendes:

%Vor%

Beachten Sie auch, dass dieser Java-Code gültig ist und in den Konstruktor int für BigDecimal aufgelöst wird:

%Vor%

Aber dieser Code schlägt auch fehl (obwohl er den int -Konstruktor verwenden sollte):

%Vor%

tl; dr: Clojure unterstützt Java interop , aber das bedeutet nicht, dass es den Regeln der Java-Sprachspezifikation folgen muss.

Was ist mit cast ?

Ein Kommentar unten fragt nach (cast) . In diesem Fall weisen Sie den Clojure-Compiler explizit an, die Typauflösung an die JVM zu delegieren. Beachten Sie den folgenden (unsinnigen) Code, der kompiliert, aber zur Laufzeit nicht ausgeführt wird:

%Vor%

Epilog II

In der Clojure-Community gab es eine ganze Reihe von Diskussionen zu diesem Thema. Bitte überprüfen Sie diese detaillierten Themen:

Verbesserte primitive Unterstützung (Rich Hickey)

Clojure 1.3 Behandlung von ganzen Zahlen und Longs (Nathan Marz)

    
noahlz 25.09.2012, 19:00
quelle
1

BigDecimal hat keinen Konstruktor für Long,

BigDecimal (BigInteger val)

%Vor%

BigDecimal (BigInteger unscaledVal, Skalierung int)

%Vor%

BigDecimal (doppelter Wert)

%Vor%

BigDecimal (Zeichenfolge val)

%Vor%

Es ist unklar, welche dieser (Long. 1) übereinstimmt. Die Funktion clojure.core.bigdec arbeitet an dieser Eingabe, indem sie ihre Eingabe an BigDec/valueOf übergibt, um das BigDecimal

zu erstellen %Vor%

verwendet diesen Aufruf:

%Vor%     
Arthur Ulfeldt 25.09.2012 19:06
quelle

Tags und Links