Подсказка типов не применяется в конструкторах defrecord - PullRequest
8 голосов
/ 27 июля 2010

Я создал тип, используя defrecord с подсказками типов для полей.Однако я обнаружил, что эти подсказки типов не применяются в конструкторах, и я могу делать с ними странные вещи.Посмотрите на фрагмент ниже, например:

user=> (defrecord Person [#^String name #^Integer age])
user.Person
user=> (seq (.getConstructors Person))
(#<Constructor public user.Person(java.lang.Object,java.lang.Object,
java.lang.Object,java.lang.Object)>
#<Constructor public user.Person(java.lang.Object,java.lang.Object)>)
user=> (Person. (Integer. 123) "abhinav")
#:user.Person{:name 123, :age "abhinav"}

Показанные подписи конструктора не соответствуют предоставленным подсказкам типов (они используют Object для String и Integer), и я могусоздавать объекты с неправильными типами полей.

Что-то не так с моим кодом или это ошибка в Clojure?

Я на Clojure 1.2.0-бета1.

Ответы [ 2 ]

9 голосов
/ 27 июля 2010

Тип-подсказки используются, чтобы избежать отражения;они (в настоящее время) не используются для статического ввода аргументов функций или конструкторов (исключение составляют примитивы, поскольку их нельзя отнести к категории Object).Таким образом, они не делают ничего для простой записи, но имеют значение, когда дело доходит до добавления реализации протокола, например:

user=> (set! *warn-on-reflection* true)
true
user=> (defprotocol P (foo [p]))
P
user=> (defrecord R [s] P (foo [_] (.getBytes s)))  ; getBytes is a method on String
Reflection warning, NO_SOURCE_PATH:6 - reference to field getBytes can't be resolved.
user.R
user=> (foo (R. 5))
java.lang.IllegalArgumentException: No matching field found: getBytes for class java.lang.Integer (NO_SOURCE_FILE:0)
user=> (defrecord R [^String s] P (foo [_] (.getBytes s)))
user.R
user=> (foo (R. 5))
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String (NO_SOURCE_FILE:0)

Разница между двумя версиями заключается в том, что последняя испускает вызов байт-кодаString.getBytecode() (следовательно, ClassCastException при передаче целого числа), тогда как первому необходимо выяснить, что именно означает .getBytes в отношении объекта времени выполнения, переданного функции (и этот процесс завершается неудачно, когда передается целое число).

6 голосов
/ 27 июля 2010

Насколько я могу судить, подсказки типов в полях deftype и defprotocol в настоящее время применяются только в случае использования примитивного типа:

(deftype Foo [^int x])

(Foo. 5)    ; => OK
(Foo. :foo) ; => no go

;; ... and likewise with defprotocol

У меня очень смутное воспоминание об этом существе.признанная проблема, хотя я не уверен, что планируется документировать это поведение или применять непримитивные подсказки ... Я постараюсь выяснить.

...