2010-07-27 17 views
7

Utworzono typ za pomocą defrecord z podpowiedziami do pól. Jednak zauważyłem, że wskazówki tego typu nie są wymuszane w konstruktorach i mogę wykonywać z nimi dziwne rzeczy. Spójrz na poniższym fragmencie na przykład:Podpowiedzi typów nie są wymuszane w konstruktorach 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"} 

Podpisy konstruktora pokazane nie zgadzają się z podpowiedzi typu świadczonych (używają Object zarówno String i Integer) i jestem w stanie zbudować obiekty z niewłaściwych typów pól.

Czy jest coś nie tak z moim kodem lub jest to błąd w Clojure?

Jestem na Clojure 1.2.0-beta1.

+3

Na marginesie, jeśli Twój kod zależy od funkcji 1.2, powinieneś preferować '^' do '# ^' do wprowadzania metadanych czytnika; stare znaczenie wyrażenia "# ^" jest przestarzałe w wersji 1.2. –

Odpowiedz

8

Wskazówki do typowania używane są w celu uniknięcia odbicia; nie są one (obecnie) używane do statycznego wpisywania argumentów funkcji lub konstruktora (wyjątkiem są prymitywy, ponieważ nie można ich podsumować pod Object). Jako takie, nie robią wiele dla prostego zapisu, ale robią sprawa, jeśli chodzi o dodanie implementacji protokołu, np:

 
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) 

Różnica pomiędzy tymi dwoma wersjami jest fakt, że emituje kod bajtowy nazywając String.getBytecode() (stąd wyjątek ClassCastException, gdy przekazano liczbę całkowitą), podczas gdy pierwsza musi sprawdzić, co dokładnie oznacza .getBytes w odniesieniu do obiektu wykonawczego przekazanego do funkcji (i proces ten kończy się niepowodzeniem po przekazaniu liczby całkowitej).

5

O ile mogę powiedzieć, podpowiedzi typu na deftype i defprotocol pola są obecnie tylko egzekwowane gdy prymitywny typ jest zaangażowany:

(deftype Foo [^int x]) 

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

;; ... and likewise with defprotocol 

mam bardzo mgliste wspomnienie to jest uznanym problemem, choć Nie jestem pewien, czy plan ma udokumentować to zachowanie, czy wymusić nie-prymitywne wskazówki ... Postaram się dowiedzieć.

Powiązane problemy