emacs-devel
[Top][All Lists]
Advanced

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

Re: Help with recursive destructive function


From: Eric Abrahamsen
Subject: Re: Help with recursive destructive function
Date: Mon, 04 Jun 2018 15:28:03 -0700
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

On 05/14/18 16:27 PM, Michael Heerdegen wrote:
> Eric Abrahamsen <address@hidden> writes:
>
>> This is great, and I really like the use of gv -- morally it seems like
>> the right tool.
>
> Didn't profile speed, however - hope it's good enough.
>
>> I will have time this weekend to apply all this to eieio-persistent.
>
> Where can I have a look at your work?

This is progressing terribly slowly, in part because of business trips,
and in part because obviously I fundamentally don't understand how
values work in elisp.

I wanted to tweak the process a bit: object slots look like: '(:slot1
"val1" :slot2 "val2"), and instead of dumping that whole list into
deep-edit, I want to call `deep-edit' once per *value*. In part that
would reduce the total number of iterations, but mostly it would make
the process more robust, avoiding a bug I hit while testing on an EBDB
database.

#+BORING_BACKGROUND
One of the slots in an EBDB database is :record-class, which defaults to
'ebdb-person-record. Let's pretend a database is created with the slots
'(:file "foo.txt" :record-class ebdb-person-record :state broken).

As `deep-edit' cdr's down the slot list, it eventually ends up with
'(ebdb-person-record :state broken), and tries to make an object out of
that, which fails.

The real solution is to have a more explicit tag saying "this should be
an object", but we don't have that now, and more importantly we won't
when it comes to reading older persistence files in a
backwards-compatible fashion.
#+END

I can't for the life of me pass values to `deep-edit' so that the
changes are reliably reflected in the original structure of "slots".
Here's a simple baseline that works correctly:

#+BEGIN src elisp
(let ((lst '(:one "one" :two ("some" "strings") :three "three")))
  (deep-edit (lambda (x) (and (stringp x) #'upcase))
             #'consp
             lst)
  lst)
#+END
=> (:one "ONE" :two ("SOME" "STRINGS") :three "THREE")

Then, naively, I call `deep-edit' on every other list item:

#+BEGIN src elisp
(let* ((lst '(:one "one" :two ("some" "strings") :three "three"))
       (len (length lst))
       (idx 1))
  (while (< idx len)
    (deep-edit (lambda (x) (and (stringp x) #'upcase))
               #'consp
               (nth idx lst))
    (cl-incf idx 2))
  lst)
#+END
=> (:one "one" :two ("SOME" "STRINGS") :three "three")

That only worked for consp values. I don't understand this: `nth' is
implemented in C as (car (nthcdr)), and nthcdr looks to me like it's
producing a chunk of the underlying list structure. So does car of
nthcdr return a simple value (ie something un-setf-able) if car is an
atom, but something still connected to the original list structure
(setf-able) if car is a cons cell?

If that's the case, I'm not sure how to reliably pass a settable value
in to `deep-edit'. We could pass gv-refs into `deep-edit', in which case
it would have to check values to see if they're already references or
not (or gv-ref itself could do that check).

I can't think of anything else. But more importantly, I'd like to know
why I'm wrong about `nth' here...

Thanks,
Eric



reply via email to

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