Hello all, Attached below is my preliminary attempt at functional record "setters". These macros generate optimal code to generate a modified copy of an existing tree of srfi-9 records, with any number of elements modified at once. I confess that this task was more difficult than I had anticipated, and it required a different approach than Ludovic had taken, because functional single-field-setters cannot be used to build an optimal functional multi-field-setter. Instead, each record type defines a '%%-modified-copy' macro that copies a record but with an arbitrary number of modified fields. This is the basis for the exported macros 'modified-copy' and 'modified-copy-nocheck' that supports arbitrarily nested records. As Ludovic warned, this requires knowledge of the record types at expansion time. To accomplish this, I enhanced srfi-9's private 'define-inlinable' macro to allow an arbitrary number of key/value pairs to be associated with the generated macro. The new macro is called 'define-tagged-inlinable', and it's used like this: (define-tagged-inlinable (key value) ... (name formals ...) body ...) where each 'key' is a private literal identifier in (srfi srfi-9). Currently, the keys '%%type', '%%index', and '%%copier' are associated with each getter, which causes the getter macro to support additional rules: ( () %%copier) ==> %%-modified-copy ( () %%type) ==> %% ( () %%index) ==> Since the keys are private to (srfi srfi-9), users cannot use these private rules without accessing srfi-9's private symbols. While I was at it, I incorporated Andy's suggestions (accessors/modifiers => getters/setters, throw-bad-struct), and made various other simplifications and improvements to the existing srfi-9 code, while being careful to remain ABI compatible with .go files compiled with earlier versions of Guile 2. Anyway, enough about the internals. The public interface I've created is quite a bit different than what we've been discussing so far. I'm open to changing it, but here's what the attached patch currently exports from (srfi srfi-9 gnu): (modified-copy ( ) ...) (modified-copy-nocheck ( ) ...) where is of the form ( ...) These macros can be used on _any_ srfi-9 record, not just ones specially declared as immutable. In fact, I have not yet gotten around to creating immutable records (with "pr" layout), though I would like to add this soon. However, I see no reason not to support 'modified-copy' on mutable records as well. Here's an example session: scheme@(guile-user)> ,use (srfi srfi-9) scheme@(guile-user)> ,use (srfi srfi-9 gnu) scheme@(guile-user)> (define-record-type :foo (make-foo x) foo? (x get-x) (y get-y set-y!)) scheme@(guile-user)> (define-record-type :bar (make-bar i j) bar? (i get-i) (j get-j set-j!)) scheme@(guile-user)> (define a (make-foo (make-bar 1 (make-foo 2)))) scheme@(guile-user)> a $1 = #<:foo x: #<:bar i: 1 j: #<:foo x: 2 y: #f>> y: #f> scheme@(guile-user)> (modified-copy a ((get-x get-i) 10) ((get-y) 14) ((get-x get-j get-y) 12)) $2 = #<:foo x: #<:bar i: 10 j: #<:foo x: 2 y: 12>> y: 14> scheme@(guile-user)> ,opt (modified-copy-nocheck a ((get-x get-i) 10) ((get-y) 14) ((get-x get-j get-y) 12)) $3 = (let ((s a)) (make-struct/no-tail :foo (let ((s (struct-ref s 0))) (make-struct/no-tail :bar 10 (let ((s (struct-ref s 1))) (make-struct/no-tail :foo (struct-ref s 0) 12)))) 14)) scheme@(guile-user)> ,opt (modified-copy a ((get-x get-i) 10) ((get-y) 14) ((get-x get-j get-y) 12)) $4 = (let ((s a)) (if (eq? (struct-vtable s) :foo) (make-struct/no-tail :foo (let ((s (struct-ref s 0))) (if (eq? (struct-vtable s) :bar) (make-struct/no-tail :bar 10 (let ((s (struct-ref s 1))) (if (eq? (struct-vtable s) :foo) (make-struct/no-tail :foo (struct-ref s 0) 12) ((@@ (srfi srfi-9) throw-bad-struct) s '%%:foo-modified-copy)))) ((@@ (srfi srfi-9) throw-bad-struct) s '%%:bar-modified-copy))) 14) ((@@ (srfi srfi-9) throw-bad-struct) s '%%:foo-modified-copy))) scheme@(guile-user)> Comments and suggestions solicited. Mark