Why can't constants be used as array dimensions in Common Lisp type specifiers?

I imagine that something like this would work:

(defconstant +len+ 3)

(deftype len-3-fixnum-array () `(array fixnum (,+len+)))

(defun foo (x)
  (declare (type len-3-fixnum-array x))
  (print x))

(foo (make-array 3 :element-type 'fixnum))
;; #(0 0 0)

(foo (make-array 4 :element-type 'fixnum))
;; The value #(0 0 0 0) is not of type (VECTOR FIXNUM 3).
;;    [Condition of type TYPE-ERROR]

However, you need to keep in mind that type annotations are only recommendations, compilers are allowed to ignore them altogether.


I.e. the problem isn't that you can't use constants in the declare form, it's that it acts as if it was quoted, so your constant there doesn't evaluate to 3, it just stays the symbol +len+.


I had the same problem with a 2D array:

(defconstant board-width  4)
(defconstant board-height 3)

(setq *board* (make-array '(board-width board-height) :initial-element 0))

I always got the error

The value BOARD-WITH is not of type SB-INT:INDEX.

So I changed the last line this way:

(setq *board* (make-array (list board-width board-height) :initial-element 0))

and it works perfectly.


If you look at the ANSI CL spec, the syntax for types is clearly defined. For simple-array:

simple-array [{element-type | *} [dimension-spec]]

dimension-spec::= rank | * | ({dimension | *}*) 

Where:

dimension---a valid array dimension.

element-type---a type specifier.

rank---a non-negative fixnum.

The valid array dimension is then explained as a fixnum.

There are no variables or constant identifiers in an simple-array type declaration. Type declarations have their own syntax and are not evaluated or similar. They are type expressions which can appear in code in special places (-> declarations).

You can use DEFTYPE to create new type names and use those, though.