guile-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: read syntax vectors immutable


From: Mark H Weaver
Subject: Re: read syntax vectors immutable
Date: Thu, 22 Jun 2017 12:44:59 -0400
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux)

j kalbhenn <address@hidden> writes:

> vectors created using read syntax are apparently immutable with guile 2.2.2:
>
> --
> (define a #(0))
> (if (vector? a) (vector-set! a 0 1))
>
> In procedure vector-set!: Wrong type argument in position 1 (expecting 
> mutable vector): #(0)
> --
>
> is this documented somewhere in the guile manual or part of the scheme 
> standard? i could not find anything about it.

R5RS section 4.1.2 (Literal expressions) states:

     As noted in section *note Storage model::, it is an error to alter
     a constant (i.e.  the value of a literal expression) using a
     mutation procedure like 'set-car!' or 'string-set!'.

Also, if you look up 'quote' in the Guile index, it says:

     Note that an application must not attempt to modify literal lists
     or vectors obtained from a ‘quote’ form, since they may be in
     read-only memory.

Although only a few types are listed above, in fact it is an error to
mutate *any* literal, regardless of its type.

In Scheme, it has always been the case that literals are supposed to be
immutable.  However, earlier versions of Guile failed to detect improper
attempts to mutate literals in most cases, and yet doing so would lead
to unspecified and often very confusing behavior.

Literals are, in effect, part of the code itself, and successfully
mutating them typically has the effect of modifying the code itself.

For example, suppose you write a procedure that returns a vector of all
zeroes, but with a '1' at a given index.  Improperly mutating vector
literals, you might try this:

  GNU Guile 2.0.11
  Copyright (C) 1995-2014 Free Software Foundation, Inc.
  
  Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
  This program is free software, and you are welcome to redistribute it
  under certain conditions; type `,show c' for details.
  
  Enter `,help' for help.
  scheme@(guile-user)> (define (mask n)
                         (let ((v '#(0 0 0 0 0 0 0 0)))
                           (vector-set! v n 1)
                           v))
  scheme@(guile-user)> (mask 3)
  $1 = #(0 0 0 1 0 0 0 0)

So far, so good.  Now let's try some other values:

  scheme@(guile-user)> (mask 6)
  $2 = #(0 0 0 1 0 0 1 0)
  scheme@(guile-user)> (mask 0)
  $3 = #(1 0 0 1 0 0 1 0)

See, you're modifying the code.  Let's disassemble 'mask' to look at its
compiled code:

  scheme@(guile-user)> ,x mask
  Disassembly of #<procedure mask (n)>:
  
     0    (assert-nargs-ee/locals 1)      ;; 1 arg, 0 locals
     2    (object-ref 1)                  ;; #(1 0 0 1 0 0 1 0) at (unknown 
file):2:32
     4    (local-ref 0)                   ;; `n'
     6    (make-int8:1)                   ;; 1
     7    (vector-set)                                          at (unknown 
file):3:25
     8    (object-ref 1)                  ;; #(1 0 0 1 0 0 1 0) at (unknown 
file):2:32
    10    (return)                        

And indeed, the code has been modified.

To create a mutable vector, use 'vector', or apply 'vector-copy' to a
literal vector.  Also note that these are shallow copies, e.g. if you
have nested vector literals, 'vector-copy' will only copy the top layer.

       Mark



reply via email to

[Prev in Thread] Current Thread [Next in Thread]