2017-06-17 4 views
1

Dieser Code ist nicht mein "echter" Code, sondern ist ein Beispiel für das Problem von einem viel größeren Algorithmus. Es hat eine Weile gedauert, bis ich (mit (set! *warn-on-reflection* true)) diese Reflexion gefunden hatte.Clojure Fehlbetrag auf Typ Inferenz

Mit Typ Hinting kommt zu dynamischen Sprachen (z. B. Python und Clojure) und aggressive Typ-Referenzierung zu anderen (z. B. Scala), scheint es seltsam, dass ich explizit mit (int ...) umgewandelt werden muss.

Warum weiß clojure nicht, dass (aget int-array int) einen int zurückgibt?

Kann ich die if-Anweisung selbst annotieren, um zu sagen, dass sie ein int zurückgibt?

Wenn nicht, kann ich eine Inline-Funktion verwenden, um die Fehler zu vermeiden.

(let [a (int-array [4 5 6 7])] 
    ;(aset a 1 (int (if (seq a) 40 (aget a 0))))) ;; fast 
    (aset a 1  (if (seq a) 40 (aget a 0)))) ;; slow 

Ich weiß, dass Typ-Hinting ist nicht weniger als die Eingabe dieses int Anruf aber das kann nicht der Fall in komplexeren Code sein.

+0

Clojure [Literal Integralzahlen] (https://clojure.org/reference/reader#_literals) sind Java Long Objekte. Deshalb müssen Sie es explizit in einen int-nativen jvm-Wert in Ihrem Code zwingen, wenn Sie einen Reflektionsaufruf vermeiden möchten. – kawas44

+0

@ kawas44 danke, dass die Perspektive auf den ersten Teil der akzeptierten Antwort hinzugefügt. –

+1

Zuerst, werfen Sie einen Blick auf aset-int, was zu sein scheint, was Sie wollen. Möglicherweise nicht relevant, aber da ich gesehen habe, dass andere darüber stolpern, dachte ich, ich würde es nur erwähnen.In clojure tendieren Sie nur dazu, int-array, aget, aset usw. zu verwenden, wenn Sie ein Java-Interop ausführen müssen, bei dem Sie Java-Arrays übergeben/empfangen müssen. Wenn Sie nur auf der Clojure-Ebene arbeiten, müssen Sie nur Clojure-Vektoren verwenden. Erwähnen Sie es, weil ich Leute aus anderen Sprachen, vor allem Java, gesehen habe, die dachten, dass sie aget/aset verwenden müssen, nur um Algorithmen zu verwenden, die Arrays verwenden. Ein Clojure-Vektor ist ein Array. –

Antwort

7

HINWEIS:

Warum nicht clojure wissen, dass (aget int-Array int) gibt ein int manuell von Clojure 1.8.0

getestet?

Es tut. Was es nicht zu wissen scheint, ist, dass (if <<condition>> Long int) ein Ergebnis zurückgibt, das zu einem primitiven int gezwungen werden könnte. Beachten Sie, dass die Reflektionswarnung verschwindet, wenn Sie stattdessen (int 40) schreiben.

Kann ich die if-Anweisung annotieren, um zu sagen, dass sie einen int zurückgibt?

Mit (int ...) ist wirklich der Weg, das zu tun. Ein int-Typ-Hinweis wäre in diesem Fall nicht korrekt, da dieser Ausdruck, wie wir gesehen haben, möglicherweise einen langen Wert zurückgibt.

Mit Type Hinting kommen, um dynamische Sprachen (zB Python und clojure) und aggressive Art Referenzierung auf andere kommen (zB Scala), scheint es seltsam, dass ich zu explicity haben gegossen mit (int ...)

Clojure ist im Wesentlichen eine dynamisch typisierte Sprache. Der Clojure-Compiler macht schon eine ganze Reihe von Typrückschlüssen - besonders lokal -, aber das ist immer noch eine Best-Effort-Basis, und ich denke nicht, dass etwas anderes erwartet werden sollte (bedenken Sie, dass die Arten der Werte nicht bekannt sind) um die Programme herum ist eine Funktion der dynamischen Typisierung). Zugegeben, das spezielle Codeschnipsel, das Sie eingefügt haben, ist für eine ganze Reihe von statischen Analysen geeignet, aber in einem typischen realen Programm, in dem Werte durch eine Vielzahl von Intermediären fließen, wäre eine solch umfassende Analyse gar nicht machbar - also warum sollte der Compiler sich aus dem Weg bringen, um ihn zu unterstützen?

+0

Das' (int 40) 'funktioniert auch überraschend. Ich hätte es nie erraten! Danke für deine Erklärung warum. –