guile-devel
[Top][All Lists]
Advanced

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

Re: Functional record "setters", a different approach


From: Ludovic Courtès
Subject: Re: Functional record "setters", a different approach
Date: Thu, 12 Apr 2012 21:58:52 +0200
User-agent: Gnus/5.110018 (No Gnus v0.18) Emacs/24.0.93 (gnu/linux)

Hi Mark!

Mark H Weaver <address@hidden> skribis:

> address@hidden (Ludovic Courtès) writes:
>> Mark H Weaver <address@hidden> skribis:
>>> 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 <struct-expr> (<field-path> <expr>) ...)
>>>   (modified-copy-nocheck <struct-expr> (<field-path> <expr>) ...)
>>>
>>> where <field-path> is of the form (<field> ...)
>>
>> I’d still want named single-field setters, for convenience.  For that,
>> we probably still need a separate ‘define-immutable-record-type’.
>
> Agreed.

Cool!  Could you integrate it somehow, along with the tests I provided?

>> Also, I’d want to avoid the term ‘copy’, which is sounds low-level;
>> ‘set’ seems more appropriate to me.  WDYT?
>
> I agree that 'copy' is not a good term to use here, especially since no
> copy is made in the zero-modification case of (modified-copy s).
>
> However, I find the term 'set' misleading, since no mutation is taking
> place.  Maybe 'update'?  I dunno, I don't have strong feelings on this.

I don’t find ‘set’ misleading because there’s no exclamation mark, and
because it’s conceptually about setting a field’s value.  WDYT?

>> Regarding the interface for multi-field nested changes, I’d still
>> prefer:
>>
>>   (set-field p (foo bar) val
>>                (foo baz) chbouib)
>>
>> Or is it less readable than:
>>
>>   (set-field p ((foo bar) val)
>>                ((foo baz) chbouib))
>
> I find the first variant to be very un-scheme-like.

Yes; in hindsight, I have the same feeling.

>> Finally, I think there’s shouldn’t be a ‘-nocheck’ version.  Dynamic
>> typing entails run-time type checking, that’s a fact of life, but safety
>> shouldn’t have to be traded for performance.
>
> Hmm.  I agree that the 'nocheck' variant should not be prominently
> mentioned, and perhaps not documented at all, but I suspect it will
> prove useful to keep it around, even if only for our own internal use to
> build efficient higher-level constructs.
>
> For example, when I built this 'modified-copy' machinery, I was unable
> to build upon the usual (<getter> s) syntax, because that would cause
> the generated code to include many redundant checks (one for each field
> retrieved).

Would these checks be alleviated by Andy’s work on peval “predicates”?

> For example, for (modified-copy s ((foo-x) 'new)) where 's' contains 10
> fields, the expanded code would include 9 separate checks that 's' is
> the right type.

Couldn’t ‘modified-copy’ be implemented differently so that there’s only
one check?  That seems like the most obvious (not necessarily the
easiest) way to address the problem.

Every time ‘car’ is used, there’s a type-check that users cannot
eliminate.  IMO, if it were to be eliminated, it should be via
orthogonal means, not via the API: for instance, when the compiler knows
the check would always pass at run-time, or with (declare (unsafe)), or
with ‘-DSCM_RECKLESS’.  A ‘car-nocheck’ wouldn’t be convenient, would it?
:-)

[...]

>> and more importantly coordinate so we don’t waste time working on the
>> same code in parallel.
>
> I started this work after you were (probably) asleep,

When I don’t sleep, I also have a daytime work, and a family, among
other things, which is why I am not this responsive.  Also, I was
assuming I was holding a mutex on this, so-to-speak.  Lastly, I check
email less frequently when I have a hack on my mind.  :-)

> and rushed to post about it before you woke up, so I did my best
> there.  If you would prefer to use your own code instead, that's okay
> with me.  As long as we end up with a functional-multi-setter that
> generates good code, I'll be satisfied.

Yeah, me too.  So I’m happy we’re getting close to an even better
solution!

>> FWIW I was using this approach to represent the tree of accessors:
>> 
>>     (define (field-tree fields)
>>       ;; Given FIELDS, a list of field-accessor-lists, return a tree
>>       ;; that groups together FIELDS by prefix.  Example:
>>       ;;   FIELDS:  ((f1 f2 f3) (f1 f4))
>>       ;;   RESULT:  ((f1 (f2 (f3)) (f4)))
>>       (define (insert obj tree)
>>         (match obj
>>           ((head tail ...)
>>            (let ((sub (or (assoc-ref tree head) '())))
>>              (cons (cons head (insert tail sub))
>>                    (alist-delete head tree))))
>>           (()
>>            tree)))
>> 
>>       (fold-right insert '() fields))
>
> I agree that this is much nicer than my corresponding code.  Thanks for
> sharing.  Would you like me to incorporate something like this into my
> code, or would you like to start with your code and maybe cherry-pick
> ideas/code from mine?  Either way is fine with me.

I’ll let you see whether/how you can borrow from this in your code, if
that’s fine with you.

Thanks,
Ludo’.



reply via email to

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