Reputation: 786
I am trying to dispatch on the type of an array. Here's a test case:
(defun column-summary2 (column)
(typecase column
(simple-double-float-vector (format t "Column is a simple-double-float-vector~%"))
;; (simple-integer-vector (format t "Column is a simple-integer-vector~%"))
;; (simple-string-vector (format t "Column is a simple-string-vector~%"))
((simple-array string (*)) (format t "~A Column is a string-array~%" column))
((simple-array float (*)) (format t "~A is a simple-float-array~%" column))
((simple-array integer (*)) (format t "~A is a simple-float-array~%" column))
(bit-vector (make-bit-vector-summary :length (length column) :count (count 1 column))))))
This works as expected for the built in type, bit-vector
, and with my own simple-double-float-vector
type:
(deftype simple-double-float-vector (&optional (length '*))
"Simple vector of double-float elements."
`(simple-array double-float (,length)))
but fails for string and integer:
LS-USER> (df::column-summary2 #("foo" "bar" "baz"))
#(foo bar baz) Column is a string-array
NIL
LS-USER> (df::column-summary2 #(1 2 3))
#(1 2 3) Column is a string-array
I tried defining types for these two:
(deftype simple-integer-vector (&optional (length '*))
"Simple vector of integer elements."
`(simple-array integer (,length)))
(deftype simple-string-vector (&optional (length '*))
"Simple vector of integer elements."
`(simple-array string (,length)))
Edit: Coerce also seems to fail:
CL-USER> (type-of (coerce #(4 4 1 1 2 1 4 2 2 4 4 3 3 3 4 4 4 1 2 1 1 2 2 4 2 1 2 2 4 6 8 2) '(simple-array integer (32))))
(SIMPLE-VECTOR 32)
CL-USER> (type-of (coerce #("foo" "bar" "baz") '(simple-array string (3))))
(SIMPLE-VECTOR 3)
but it doesn't help. It seems that integer
and string
are always conflated. Can anyone see why?
Upvotes: 3
Views: 90
Reputation: 9282
typecase
can only distinguish types that are implementationally distinct, and it is very unlikely that arrays of integer
s and strings
are. You can test this by, for instance:
(eq (upgraded-array-element-type 'integer)
(upgraded-array-element-type 'string))
Which will very likely return t
. And in fact it's likely that upgraded-array-element-type
on both these types is itself t
: the most specialised array that can store a general string
is the same as the one that can store a general integer
, since both of these types really require the elements of the array to be general pointers.
The thing here is that when typecase
sees an array all it can dispatch on is the implementational type of the array, rather than anything else and those two types are the same in many cases where they are not the same conceptually.
Upvotes: 4
Reputation: 51521
An array's type can only be the type given to make-array
as its :element-type
, see type simple-array
in the spec. If you use array literals, that is likely not the case.
It does not check at runtime the type of each element.
The word can is a hint that this is also influenced by the upgrading of array element types: there is only a fixed set (implementation defined) of array types, mostly determined by whether there is a specialized representation. The actual array element type is the most specialized of that set that fits the declared type.
If you need the exact information at runtime, you need to wrap and tag yourself.
Upvotes: 2