vectorcommon-lisppractical-common-lisp

How to protect vector from resizing?


So I am going through Practical Common Lisp once again and I cannot really understand how to create a vector with constant size.

According to the book:

However, even a vector with a fill pointer isn't completely resizable. The vector *x* can hold at most five elements. To make an arbitrarily resizable vector, you need to pass MAKE-ARRAY another keyword argument: :adjustable.

However when I use (vector-push-extend) I can extend my initial vector even when I set :adjustable nil (or leave it default).

(vector-push 'a *x*) ;; 0
(vector-push 'b *x*) ;; 1
(vector-push 'c *x*) ;; 2
(vector-push 'd *x*) ;; 3
(vector-push 'e *x*) ;; 4
*x* ;; #(A B C D E)
(vector-push 'f *x*) ;; NIL
*x* ;; #(A B C D E)
(vector-push-extend 'f *x*) ;; 5
*x* ;; #(A B C D E F)

I assumed that (vector-push-extend) cannot resize array which is not :adjustable? What is the correct way of creating non-dynamic (non-adjustable) array?


Solution

  • The behavior is implementation specific.

    The Common Lisp specification says:

    There is no specified way to create an array for which adjustable-array-p definitely returns false.

    An implementation may make vectors adjustable, even though the :adjustable argument to make-array is given as nil.

    To see if an array object is actually adjustable, one needs to call adjustable-array-p.

    The Common Lisp standard says that a vector is expressly adjustable (and thus also actually adjustable if it was requested to be so. If it wasn't request, the vector can still be adjustable, actually adjustable.

    So the :adjustable nil arg is just telling Lisp, that it can make the vector non-adjustable, if possible.

    Here in SBCL:

    1) A normal vector is not adjustable:

    * (make-array 5)
    #(0 0 0 0 0)
    * (adjustable-array-p *)
    NIL
    

    2) A vector with a fill-pointer is actually adjustable in SBCL:

    * (make-array 5 :fill-pointer 0)
    #()
    * (adjustable-array-p *)
    T
    

    3) A vector with a fill-pointer is actually adjustable in SBCL, even though the :adjustable arg was given as nil:

    * (make-array 5 :fill-pointer 0 :adjustable nil)
    #()
    * (adjustable-array-p *)
    T
    

    That's in SBCL. In LispWorks 2) and 3) would not be actually adjustable.