unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: Mark H Weaver <mhw@netris.org>
To: ludo@gnu.org (Ludovic Courtès)
Cc: guile-devel@gnu.org
Subject: Re: Functional record "setters", a different approach
Date: Thu, 12 Apr 2012 11:04:13 -0400	[thread overview]
Message-ID: <874nsp800i.fsf@netris.org> (raw)
In-Reply-To: <87r4vthpti.fsf@gnu.org> ("Ludovic \=\?utf-8\?Q\?Court\=C3\=A8s\=22'\?\= \=\?utf-8\?Q\?s\?\= message of "Thu, 12 Apr 2012 00:22:01 +0200")

Hi Ludovic!

ludo@gnu.org (Ludovic Courtès) writes:
> Mark H Weaver <mhw@netris.org> 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.

> 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.

> 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.  One could make the
same argument about 'let', 'let-values', or 'cond', but the Scheme
community has consistently chosen the latter style of syntax.  The
latter style allows better extensibility.  Also, the 'syntax-rules'
pattern matching machinery works very nicely with the usual scheme
syntax, and poorly for your proposed syntax.  I feel fairly strongly
about this.

> 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).

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.  Even when our compiler becomes smart enough to
eliminate those redundant checks, it creates a lot of extra work for the
compiler, slowing everything down, and of course when interpreting (or
compiling without optimization) it is a serious lose.

Therefore, I needed a 'nocheck' version of the individual getters, so
that I could check the type just once and then fetch each individual
field without additional checks.  Unfortunately, there was none, so I
needed I hack around this limitation, adding a mechanism to retrieve the
field-index from a getter at expansion time, and then using 'struct-ref'
directly.  This is ugly.  I'd have preferred to have a 'nocheck' getter
instead.

In summary, my view is that in order to enable practical elegant
programming for users, we sometimes need to do less elegant (or even
downright ugly) things in the lower levels.  Otherwise the system will
be too slow, and users will reject elegant constructs such as functional
setters and just use plain mutation instead.

>> These macros can be used on _any_ srfi-9 record, not just ones specially
>> declared as immutable.
>
> I assume this preserves “ABI” compatibility too, right?

Yes.

> However, in the future, could you please reply in the same thread,

You're right, I should have done so.

> 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, 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.

> 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.

    Thanks!
      Mark



  reply	other threads:[~2012-04-12 15:04 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-04-11  6:59 Functional record "setters", a different approach Mark H Weaver
2012-04-11  7:57 ` Mark H Weaver
2012-04-11  8:20   ` Mark H Weaver
2012-04-11 22:27     ` Ludovic Courtès
2012-04-11 22:22 ` Ludovic Courtès
2012-04-12 15:04   ` Mark H Weaver [this message]
2012-04-12 16:45     ` Thien-Thi Nguyen
2012-04-12 19:58     ` Ludovic Courtès
2012-04-13  1:58       ` Mark H Weaver
2012-04-13 15:41         ` Ludovic Courtès
2012-04-13 17:26           ` Mark H Weaver
2012-05-07 16:34         ` Ludovic Courtès
2012-05-14 22:25           ` Mark H Weaver
2012-05-15 21:23             ` Ludovic Courtès
2012-11-07 20:04 ` Mark H Weaver
2012-11-08  5:15   ` Mark H Weaver
2012-11-08 19:09     ` Ludovic Courtès
2012-11-09  3:54       ` Mark H Weaver
2012-11-10 16:28         ` Ludovic Courtès
2012-11-10 19:03           ` Mark H Weaver
2012-11-10 21:40             ` Ludovic Courtès
2012-11-10  4:13       ` Mark H Weaver

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=874nsp800i.fsf@netris.org \
    --to=mhw@netris.org \
    --cc=guile-devel@gnu.org \
    --cc=ludo@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).