Clojure экземпляр? единственный аргумент
Меня немного смущает функция clojure instance?
. Кажется вполне счастливым принять один аргумент. Так
(instance? String)
работает нормально, но всегда возвращает false.
Я что-то упустил? Я делал это дважды за два дня, и в оба раза мне потребовалось довольно много времени, чтобы отлаживать (да, я согласен, сделать ошибку однажды можно считать несчастьем, но в два раза выглядит небрежно).
Почему он не прерывается, с ошибкой arity?
Примечание добавлено позже:
Начиная с clojure 1.6 это исправлено!
http://dev.clojure.org/jira/browse/CLJ-1171
Ответы
Ответ 1
Интересно... хотя instance?
определяется в core.clj
, кажется, что в формах clojure.lang.Compiler
для (instance?)
имеется специальная обработка для (instance?)
.
Compiler.java, строка 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)));
}
}
Я интерпретирую это как означающее, что при компиляции/оценке формы (instance?)
функция, определенная в core.clj
, игнорируется в пользу жесткого поведения, которое интерпретирует отсутствующий второй аргумент как nil
, Я предполагаю, что это сделано по соображениям производительности, как своего рода подкладка.
Очевидно, что эта специальная обработка применяется только в определенных случаях (и я недостаточно знаком с компилятором, чтобы узнать, что это такое). Как показано в ответе Ankur, существуют способы вызова instance?
, которые вызывают функцию, определенную в core.clj
для вызова.
Ответ 2
Я думаю, что это ошибка. Если вы определяете новую версию экземпляра?, например,
(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))))
вы получите ожидаемое исключение
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)
Ответ 3
Если вы посмотрите на instance?
code, вы увидите, что метод Class
вызывается:
(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))))
Похоже, что под капотом nil
(или false
) считается значением по умолчанию для параметра x
при передаче к isInstance
и возвращает false
.
Ответ 4
Хм.... интересно... все приведенные ниже вызовы терпят неудачу (как это и должно быть):
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)
Событие, создающее новый экземпляр экземпляра? функциональный объект работает так, как он должен работать:
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