2012-11-01 20 views
13

Sono un po 'confuso dalla funzione clojure instance?. Sembra abbastanza felice di prendere una sola discussione. Quindiistanza di clojure? argomento singolo

(instance? String) 

funziona bene, ma restituisce sempre false.

mi manca qualcosa qui? L'ho fatto due volte in due giorni, e in entrambe le occasioni mi ci è voluto un po 'di tempo per eseguire il debug (sì, sono d'accordo, fare l'errore una volta può essere considerato una disgrazia, ma due volte sembra una disattenzione).

Perché non si interrompe, con un errore di integrità?

Nota aggiunta in seguito: A partire da Clojure 1.6 questo problema è stato risolto!

http://dev.clojure.org/jira/browse/CLJ-1171

+0

È anche possibile chiamare l'istanza? con più di 2 argomenti: '(instance? String" a "0)' -> 'true' – Alex

+0

' (istanza?String "a" 0) 'fornisce l'errore ArityException – amirteymuri

risposta

8

interessante ... anche se instance? è definito in core.clj, sembra che ci sia una gestione speciale integrato nel clojure.lang.Compiler per (instance?) forme.

Compiler.java, line 3498:

if(fexpr instanceof VarExpr && ((VarExpr)fexpr).var.equals(INSTANCE)) 
     { 
     if(RT.second(form) instanceof Symbol) 
      { 
      Class c = HostExpr.maybeClass(RT.second(form),false); 
      if(c != null) 
       return new InstanceOfExpr(c, analyze(context, RT.third(form))); 
      } 
     } 

ho interpretare tale nel senso che, quando si compila/valutare una forma (instance?), la funzione definita in core.clj viene ignorato a favore del comportamento hard-wired, che non interpretano un mancante secondo argomento come nil. Immagino che questo sia fatto per motivi di prestazioni, come una sorta di in-lining.

Apparentemente questa gestione speciale si applica solo in alcuni casi (e non sono abbastanza familiare con il compilatore per sapere cosa sono). Come illustrato dalla risposta di Ankur, ci sono modi per chiamare instance? che fanno invocare la funzione definita in core.clj.

+0

Il percorso veloce nel compilatore (che emette un'istanza di espressione) viene eseguito quando la chiamata è una chiamata diretta con un simbolo che denota direttamente una classe. – Bendlas

+0

C'è un biglietto per questo ora: http://dev.clojure.org/jira/browse/CLJ-1171 – Bendlas

2

Se si guarda al instance? code si vedrà che il metodo isInstance di Class si chiama:

(def 
    ^{:arglists '([^Class c x]) 
     :doc "Evaluates x and tests if it is an instance of the class 
      c. Returns true or false" 
     :added "1.0"} 
    instance? (fn instance? [^Class c x] (. c (isInstance x)))) 

Sembra che sotto il cofano, nil (or false) è considerato come il valore predefinito per x parametro passato allo isInstance e restituisce false.

+1

Questo da solo non riesce a spiegare il comportamento osservato, poiché altre funzioni definite in questo modo generano eccezioni di arity quando vengono chiamate con il numero errato di argomenti. – Alex

+0

Hai ragione. Non ho provato con la mia versione di questa funzione. Colpa mia. E sembra che questo "problema" persista da Clojure 1.3: https://groups.google.com/forum/?fromgroups=#!topic/clojure-dev/OmmqMyd_uXE –

+0

Interessante. Ho cercato un ticket suggerito da questo thread e non sono riuscito a trovarlo. Immagino sia caduto sotto il filo. Vedrò se riesco a capire come inviare una nuova segnalazione di bug. In caso contrario, suppongo che avvolgere istanza? per adesso. –

3

Penso che sia un bug. Se definisci una nuova versione di istanza ?, ad es.

(def 
^{:arglists '([^Class c x]) 
    :doc "Evaluates x and tests if it is an instance of the class 
     c. Returns true or false" 
    :added "1.0"} 
foo? (fn foo? [^Class c x] (. c (isInstance x)))) 

si otterrà l'eccezione prevista

user=> (foo? String "bar") 
true 
user=> (foo? String 1) 
false 
user=> (foo? String) 
ArityException Wrong number of args (1) passed to: user$foo-QMARK- clojure.lang.AFn.throwArity (AFn.java:437) 
2

Hmm .... interessanti ... tutte le chiamate sotto fallisce (che è come dovrebbe essere):

user=> (.invoke instance? String) 
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437) 

user=> (instance? (type "")) 
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437) 

user=> (apply instance? String []) 
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437) 

user=> (#'instance? Long) 
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437) 

Evento che crea una nuova istanza di "istanza?" oggetto funzione funziona come dovrebbe funzionare:

user=> (def a (.newInstance (aget (.getConstructors (type instance?)) 0) (into-array []))) 
#'user/a 
user=> (a String) 
ArityException Wrong number of args (1) passed to: core$instance-QMARK- clojure.lang.AFn.throwArity (AFn.java:437) 
user=> (a String "") 
true 
Problemi correlati