by Peter McGoron
For editor's use only. Please do not edit this section.
??? the draft/final/withdrawn status of the SRFI, information on how to subscribe to its mailing list, and important dates in its history. The editor will add this section.
The Reports designate certain values as immutable,
such as the returned string in symbol->string and quoted
data. The R7RS makes it an
error to mutate these values, while the
R6RS says that implementations
should raise an &assertion error on mutation.
This SRFI exports a minimalistic API to query if a value is immutable,
and to construct immutable values.
This SRFI only encompasses the behavior of some implementations. The full spectrum of behavior across all implementations is difficult to capture. For instance, the following code
(define (f) '(1 2))
(let ((a (f)) (b (f)))
(set-car! a 10)
(set-car! b 20)
(values (eqv? a b) (car a)))
evaluates to #t 20 on CHICKEN 5 and Chez 10 without any
errors. In this case, the immutable
value '(1 2) is
only allocated once, and it is an error to modify it in that it can cause
unexpected behavior. But it does not raise an error on modification.
In general, optimizations could make the mutation of literal values very difficult to reason about if they are not tagged in a way compatible with this SRFI.
There is no portable way to query if a value is immutable. For instance,
the following mutating map:
(define (map! f lst)
(do ((lst lst (cdr lst)))
((null? lst))
(set-car! lst (f (car lst)))))
will have non-portable behavior when passed a quoted list:
(let ((l '((1 2) (3 4))))
(map! car l)
l) ⇒ error
Since this is an error,
anything can happen, and there is no way
to guard against surprising behavior because there is no way to check that
the list is immutable.
Many implementations flag literal values and raise an exception when they are modified. Examples include TR7, Chibi, STklos, Gauche, and Sagittarius. This SRFI specifies an API to query if a value is immutable, and a predicate for exceptions that are raised when one attempts to modify an immutable value.
All of these implementations allow for immutable values to be created on-the-fly (for instance, through the REPL). Because of this, this SRFI also specifies an API for creating immutable versions of the basic Scheme containers. Since some ahead-of-time compilers may wish to store literal values in read-only memory, this feature is not required of all implementations of this SRFI.
Procedure and argument names follow the same naming conventions as the R7RS.
Non-normative text is in small text.
The SRFI is organized into multiple libraries: (SRFI ###)
is required. The other libraries may not be
available on all implementations of this SRFI: if they are, then
they must export all of their specified procedures.
All mutating procedures in the Report (like set-car!,
string-set!,
etc.) must raise an error that satisfies the
predicate mutability-error? if they attempt to mutate an immutable
value. They must not modify any immutable object.
Some objects may be made up of both mutable and immutable objects: one example is a list made up of mutable and immutable pairs. Attempting to mutate the immutable pairs would raise an exception, while mutating the mutable pairs works as expected.
(immutable? obj)
(SRFI ###)Returns #t if the object is immutable. An
immutable object is any such object designated as such by the Reports,
along with any implementation-defined objects.
This procedure may return #f on objects that are never
mutable, like numbers and record types with no setters. However, if it
is possible to create a record type in both mutable and immutable
variants, then this procedure must be able to
differentiate between the two.
(immutable? '(1 2)) ⇒ #t
(ilist? obj)
(SRFI ###)Returns #t if the list is an immutable list.
An immutable list is either the empty list, or an immutable pair whose cdr is an immutable list.
(mutability-error? obj)
(SRFI ###)Predicate for errors raised from mutating procedures attempting to mutate immutable objects.
(ipair obj1 obj2)
(SRFI ### constructors)Returns an immutable pair object.
This procedure is not named icons because of potential
confusion with the concept of an icon.
(define p (ipair 1 2))
(immutable? p) ⇒ #t
(equal? p (cons 1 2)) ⇒ #t
(pair? p) ⇒ #t
(set-car! p 10) ⇒ error
(list? (cons 1 (ipair 2 (cons 3 '())))) ⇒ #t
(ilist obj1 …)
(SRFI ### constructors)Returns a list made up of immutable pairs.
(list? (ilist 1 2)) ⇒ #t
(ilist? (ilist 1 2)) ⇒ #t
(equal? (ilist 1 2) (list 1 2)) ⇒ #t
(list->ivector list)
(SRFI ### constructors)Returns an immutable vector whose elements are the elements of list.
(list->ibytevector list)
(SRFI ### constructors)Returns an immutable bytevector whose elements are the elements of list.
(list->istring list)
(SRFI ### constructors)Returns an immutable string whose elements are the elements of list.
(can-make-immutable? obj)
(SRFI ### make-immutable)Returns #t if the object can be passed to make-immutable!,
and #f otherwise. Pairs, vectors, bytevectors, and strings
must return #t for this procedure.
(make-immutable! obj)
(SRFI ### make-immutable)It is an error if the object is not can-make-immutable?.
Makes the object immutable, such that after execution of this procedure,
(immutable? obj) returns #t.
The SRFI is not portably implementable. An implementation for TR7 will be made soon.
John Cowan had the idea for the API.
© 2026 Peter McGoron.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.