2012-11-01 11 views
13

Jestem trochę zdezorientowany funkcją clojure instance?. Wydaje się być całkiem szczęśliwym z powodu pojedynczego argumentu. Tak więcinstancja clojure? pojedynczy argument

działa poprawnie, ale zawsze zwraca wartość false.

Czy tu czegoś brakuje? Zrobiłem to dwa razy w ciągu dwóch dni, i za każdym razem zajmowanie mnie przez dłuższy czas trwało (tak, zgadzam się, aby błąd był niegdyś uważany za nieszczęście, ale dwa razy wygląda na niedbalstwo).

Dlaczego nie pęka, z błędem arytmu?

Uwaga dodana później: Od wersji Clojure 1.6 zostało to naprawione!

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

+0

Możesz również wywołać instancję? z więcej niż 2 argumentami: '(instancja? String" a "0)' -> 'true' – Alex

+0

' (instancja?Łańcuch "a" 0) 'daje błąd ArityException – amirteymuri

Odpowiedz

8

Ciekawe ... chociaż instance? jest zdefiniowana w core.clj, wydaje się, że istnieje specjalna obsługa wbudowana w clojure.lang.Compiler dla (instance?) formach.

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))); 
      } 
     } 

interpretuję to oznaczać, że podczas kompilacji/ocenić formę (instance?) funkcja zdefiniowana w core.clj jest ignorowana na rzecz ciężko przewodowy zachowanie, które ma interpretować brakujący drugi argument jako nil. Zgaduję, że robi się to ze względów wydajnościowych, jako swego rodzaju in-undering.

Wygląda na to, że ta szczególna obsługa ma zastosowanie tylko w niektórych przypadkach (i nie jestem dostatecznie zaznajomiony z kompilatorem, aby wiedzieć, co to jest). Jak ilustruje odpowiedź Ankur, istnieją sposoby wywoływania instance?, które powodują wywołanie funkcji zdefiniowanej w core.clj.

+0

Szybka ścieżka kompilatora (która emituje wyrażenie instanceof) jest pobierana, gdy wywołanie jest bezpośrednim połączeniem z symbolem bezpośrednio oznaczającym klasę. – Bendlas

+0

Jest już bilet na to: http://dev.clojure.org/jira/browse/CLJ-1171 – Bendlas

2

Jeśli spojrzeć na instance? code widać, że metoda isInstance z Class nazywa się:

(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)))) 

Wygląda pod maską, nil (or false) jest traktowany jako wartość domyślną dla x parametrze po przekazaniu do isInstance i zwraca false.

+1

Samo to nie wyjaśnia zaobserwowanego zachowania, ponieważ inne funkcje zdefiniowane w ten sposób powodują wyjątki arith, gdy są wywoływane z niepoprawną liczbą argumentów. – Alex

+0

Masz rację. Nie testowałem z własną wersją tej funkcji. Mój błąd. Wygląda na to, że "problem" trwa od czasu Clojure 1.3: https://groups.google.com/forum/?fromgroups=#!topic/clojure-dev/OmmqMyd_uXE –

+0

Interesujące. Szukałem biletu sugerowanego przez ten wątek i nie mogłem go znaleźć. Sądzę, że spadł pod drutem. Zobaczę, czy mogę się dowiedzieć, jak przesłać nowy raport o błędzie. Jeśli to nie zadziała, to chyba będę owijać instancję? Na razie. –

3

Myślę, że to błąd. Jeśli zdefiniujesz nową wersję instancji ?, np.

(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)))) 

otrzymasz oczekiwany wyjątek

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 .... ciekawe ... wszyscy poniżej połączenia nie powiedzie się (co jest, jak to ma być):

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) 

Wydarzenie tworzące nowe wystąpienie "instancji?" Obiekt funkcja działa tak jak ma działać:

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