From: Edi Weitz
Subject: Two question about ADJUST-ARRAY and array displacement
Date: 
Message-ID: <87znfh6n43.fsf@bird.agharta.de>
Hi!

I have two questions about ADJUST-ARRAY. The first one is whether code
like the following is illegal:

  (let* ((a (make-array 10 :adjustable t))
         (b (make-array 10 :displaced-to a)))
    (adjust-array a 3)
    b)

I searched the HyperSpec and CLtL2 and could not find a place where
this is explicitely forbidden. However, it seems intuitively clear to
me that it can't be OK. A quick check with the Lisps installed on my
machine shows that only the ones based on Python accept it.

1. CMUCL 18e and SBCL 0.8.4.39

   #(0 0 0 0 0 0 0 0 0 0)

2. CLISP 2.31

   *** - An array has been shortened by adjusting it while another array was displaced to it.

3. AllegroCL 6.2 trial

   #(NIL NIL NIL
     #<Printer Error, obj=#x71000985: Index(s) to array function is/are out of the range of the array.>)

4. LispWorks 4.2.7 professional

   #(NIL NIL NIL 0 #<pointer out of bounds 00280013> 65792 2 2 #<pointer out of bounds 00003832> 0)

5. ECL 0.9

   Can't keep displacement.
   Broken at ADJUST-ARRAY.

The other question is about the wording in the CLHS. In my
understanding (please correct me if I'm wrong) the purpose of
ADJUST-ARRAY is that this function returns an array which is EQ to the
original array if that one was "actually adjustable." If the original
array was not "actually adjustable" then a newly created array might
be returned. This seems to be supported by CLtL2 and the X3J13 Cleanup
Issue ADJUST-ARRAY-NOT-ADJUSTABLE.

However, the CLHS says that the result of ADJUST-ARRAY is "either the
modified array, or a newly created array to which ARRAY can be
displaced." I wonder why the phrase "to which ARRAY can be displaced"
is there and what it means.

Suppose I have an array A which is not actually adjustable and
(ADJUST-ARRAY A <n>) returns the new array B. How am I supposed to
displace A to B?

And what if I use ADJUST-ARRAY to make A smaller? How can the
resulting array be such that the original can be displaced to it?

OK, and I wasn't quite honest - here's a third little question: I
gather that if my code looks like this

  (defun foo ()
    (let (b)
      (let ((a (make-array 10 :initial-element 0)))
        (setf (aref a 9) 42)
        (setq b (make-array 10 :displaced-to a)))
      b))

A won't be garbage-collected as long as B isn't garbage,
i.e. displacing B to A effectively creates a "reference" from B to
A. The implementations mentioned above all seem to support this point
of view but I thought I'd better ask while I'm at it. (And, yes, I
know that the standard doesn't mention GC... :)

Thanks in advance for your help,
Edi.

From: Barry Margolin
Subject: Re: Two question about ADJUST-ARRAY and array displacement
Date: 
Message-ID: <QdCob.324$lK3.17@news.level3.com>
In article <··············@bird.agharta.de>, Edi Weitz  <···@agharta.de> wrote:
>Hi!
>
>I have two questions about ADJUST-ARRAY. The first one is whether code
>like the following is illegal:
>
>  (let* ((a (make-array 10 :adjustable t))
>         (b (make-array 10 :displaced-to a)))
>    (adjust-array a 3)
>    b)
>
>I searched the HyperSpec and CLtL2 and could not find a place where
>this is explicitely forbidden. However, it seems intuitively clear to
>me that it can't be OK. A quick check with the Lisps installed on my
>machine shows that only the ones based on Python accept it.

Both CLTL2 and the CLHS dictionary entry for ADJUST-ARRAY say:

If A is displaced to B, the consequences are unspecified if B is adjusted
in such a way that it no longer has enough elements to satisfy A.

>The other question is about the wording in the CLHS. In my
>understanding (please correct me if I'm wrong) the purpose of
>ADJUST-ARRAY is that this function returns an array which is EQ to the
>original array if that one was "actually adjustable." If the original
>array was not "actually adjustable" then a newly created array might
>be returned. This seems to be supported by CLtL2 and the X3J13 Cleanup
>Issue ADJUST-ARRAY-NOT-ADJUSTABLE.
>
>However, the CLHS says that the result of ADJUST-ARRAY is "either the
>modified array, or a newly created array to which ARRAY can be
>displaced." I wonder why the phrase "to which ARRAY can be displaced"
>is there and what it means.
>
>Suppose I have an array A which is not actually adjustable and
>(ADJUST-ARRAY A <n>) returns the new array B. How am I supposed to
>displace A to B?

The corresponding wording in CLTL was "ADJUST-ARRAY may, depending on the
implementation and the arguments, simply alter the given array or create
and return a new one.  In the latter case the given array will be altered
so as to be displaced to the new array and have the given new dimensions."

Thus, it's not you that can displace it, but the implementation.  Perhaps
better wording would have been "to which ARRAY will have been displaced."

>And what if I use ADJUST-ARRAY to make A smaller? How can the
>resulting array be such that the original can be displaced to it?

I don't think this causes a problem with the above understanding of the
wording.

>OK, and I wasn't quite honest - here's a third little question: I
>gather that if my code looks like this
>
>  (defun foo ()
>    (let (b)
>      (let ((a (make-array 10 :initial-element 0)))
>        (setf (aref a 9) 42)
>        (setq b (make-array 10 :displaced-to a)))
>      b))
>
>A won't be garbage-collected as long as B isn't garbage,
>i.e. displacing B to A effectively creates a "reference" from B to
>A. The implementations mentioned above all seem to support this point
>of view but I thought I'd better ask while I'm at it. (And, yes, I
>know that the standard doesn't mention GC... :)

Clearly A can't be GC'ed -- nothing can be collected if there are any
references to it.

However, a smart implementation could conceivably detect that the only
reference to A is via the displacement from B.  When all other references
to A disappear, the GC could merge them into a single object.  There's no
standard function to return the target of a displaced array, so this merger
would be undetectable unless you used implementation-dependent, internal
functions.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Edi Weitz
Subject: Re: Two question about ADJUST-ARRAY and array displacement
Date: 
Message-ID: <87r80t6k1t.fsf@bird.agharta.de>
On Fri, 31 Oct 2003 23:27:44 GMT, Barry Margolin <··············@level3.com> wrote:

> Both CLTL2 and the CLHS dictionary entry for ADJUST-ARRAY say:
>
> If A is displaced to B, the consequences are unspecified if B is
> adjusted in such a way that it no longer has enough elements to
> satisfy A.

Argh! I can't understand how I managed to overlook this although I've
read this several times. Sorry for the noise.

> The corresponding wording in CLTL was "ADJUST-ARRAY may, depending
> on the implementation and the arguments, simply alter the given
> array or create and return a new one.  In the latter case the given
> array will be altered so as to be displaced to the new array and
> have the given new dimensions."
>
> Thus, it's not you that can displace it, but the implementation.
> Perhaps better wording would have been "to which ARRAY will have
> been displaced."

OK, I see.

But that doesn't mean that arrays which were displaced to the adjusted
array will "inherit" the implicit displacement of ADJUST-ARRAY. I
would have expected that an intended consequence would have been that
the following code

  (let* ((a (make-array 10 :initial-element 0))
         (b (make-array 10 :displaced-to a)))
    (let ((c (adjust-array a 100)))
      (setf (aref c 1) 42)
      (aref b 1)))

will return 42 but it doesn't. (Rationale: B is displaced to A, and
ADJUST-ARRAY returns C to which A is displaced, thus B is indirectly
displaced to C.)

It rather seems that adjusting an array which isn't actually
adjustable will break all displacements to this array. Right?

> Clearly A can't be GC'ed -- nothing can be collected if there are
> any references to it.
>
> However, a smart implementation could conceivably detect that the
> only reference to A is via the displacement from B.  When all other
> references to A disappear, the GC could merge them into a single
> object.  There's no standard function to return the target of a
> displaced array, so this merger would be undetectable unless you
> used implementation-dependent, internal functions.

What about ARRAY-DISPLACEMENT?

Thanks,
Edi.
From: james anderson
Subject: Re: Two question about ADJUST-ARRAY and array displacement
Date: 
Message-ID: <3FA2FBB9.F13CBADE@setf.de>
Edi Weitz wrote:
> 
> On Fri, 31 Oct 2003 23:27:44 GMT, Barry Margolin <··············@level3.com> wrote:
> 
> ...
> >
> > Thus, it's not you that can displace it, but the implementation.
> > Perhaps better wording would have been "to which ARRAY will have
> > been displaced."
> 
> OK, I see.
> 
> But that doesn't mean that arrays which were displaced to the adjusted
> array will "inherit" the implicit displacement of ADJUST-ARRAY. I
> would have expected that an intended consequence would have been that
> the following code
> 
>   (let* ((a (make-array 10 :initial-element 0))
>          (b (make-array 10 :displaced-to a)))
>     (let ((c (adjust-array a 100)))
>       (setf (aref c 1) 42)
>       (aref b 1)))
> 
> will return 42 but it doesn't. (Rationale: B is displaced to A, and
> ADJUST-ARRAY returns C to which A is displaced, thus B is indirectly
> displaced to C.)
> 
> It rather seems that adjusting an array which isn't actually
> adjustable will break all displacements to this array. Right?
> 

thus the passage in cltl2 which admonishes that the original may be unchanges,
and one must treat it as delete/nconc under those conditions.

...