user3185284
user3185284

Reputation: 65

how to specify element type in vector of sbcl (or common lisp)?

I tried following code in sbcl 1.1.14, but it seems the type check ignores the declaration for the vector element.

(defun test (vec)
  (declare (type (vector integer) vec))
  (format nil "~a~&" (elt vec 0)))

Any hint? Thank you!

Upvotes: 3

Views: 2553

Answers (1)

Rainer Joswig
Rainer Joswig

Reputation: 139241

Note first that taking declarations as type checks is nothing that is provided by standard ANSI Common Lisp. That's an extension which was introduced with CMUCL. SBCL is a descendant of CMUCL.

The way the Common Lisp type system works for vectors and arrays is slightly unusual.

The Element Type.

Arrays are being created with an element type. This means that the Lisp system will create an array which can store elements of that type. But Common Lisp does not require that for each element type there are specialized versions of arrays. If a specialized version of an array is not available, then the element type is upgraded to the next 'larger' type.

Example for Element Type Upgrading

CL-USER 14 > (upgraded-array-element-type '(unsigned-byte 1))
(UNSIGNED-BYTE 1)

CL-USER 15 > (upgraded-array-element-type '(unsigned-byte 2))
(UNSIGNED-BYTE 2)

So there are array versions optimized for (unsigned-byte 1) and (unsigned-byte 2).

CL-USER 16 > (upgraded-array-element-type '(unsigned-byte 3))
(UNSIGNED-BYTE 4)

OOPS! There is no array optimized for (unsigned-byte 3). If you request such an array, you will get a slightly larger one, for (unsigned-byte 4).

CL-USER 17 > (upgraded-array-element-type '(unsigned-byte 4))
(UNSIGNED-BYTE 4)

CL-USER 18 > (upgraded-array-element-type '(unsigned-byte 5))
(UNSIGNED-BYTE 8)

CL-USER 19 > (upgraded-array-element-type 'integer)
T

Above shows that there is no special array for integers. You'll get a general array instead.

Your Code

(defun test (vec)
  (declare (type (vector integer) vec))
  (format nil "~a~&" (elt vec 0)))

So your declaration here really means this:

The variable vec is bound to a vector which can held integer numbers.

IT DOES NOT MEAN:

The variable vec is bound to a vector which only helds integer numbers.

CL-USER 21 > (typep '#(a "b" #\c) '(vector integer))
T

The above returns true in my Lisp, because the vector is a general vector and it can store integers. So it checks the type of the vector, but it does not care if the contents of the vector are actually all of type integer. It just says, that the vector COULD contain integer numbers.

Predicate-based type checks

Common Lisp allows type declarations to use predicates.

CL-USER 28 > (defun vector-of-numbers-p (vector)
               (and (typep vector 'vector)
                    (every 'integerp vector)))
VECTOR-OF-NUMBERS-P

CL-USER 29 > (typep '#(a "b" #\c) '(satisfies arrayp))
T

CL-USER 30 > (typep '#(a "b" #\c) '(satisfies vector-of-numbers-p))
NIL

CL-USER 31 > (typep '#(1 2 3) '(satisfies vector-of-numbers-p))
T

But checking that at compile-time? Probably not.

Upvotes: 13

Related Questions