Введите вывод подсказок, не осуществленный в defrecord конструкторах

Я создал использование типа 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?

Я нахожусь на 1.2.0-beta1 Clojure.

9
задан Abhinav Sarkar 27 July 2010 в 14:52
поделиться

2 ответа

Подсказки типов используются для того, чтобы избежать отражения; они не используются (в настоящее время) для статической типизации аргументов функций или конструкторов (исключением являются примитивы, поскольку они не могут быть подчинены 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 при передаче Integer), в то время как в первом случае нужно посмотреть, что именно .getBytes означает в отношении объекта времени выполнения, переданного в функцию (и этот процесс не удается при передаче Integer).

9
ответ дан 4 December 2019 в 13:44
поделиться

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

(deftype Foo [^int x])

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

;; ... and likewise with defprotocol

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

6
ответ дан 4 December 2019 в 13:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: