> Le 29/06/2021 22:45, David Kastrup <d...@gnu.org> a écrit : > > > Aaron Hill <lilyp...@hillvisions.com> writes: > > > On 2021-06-29 1:20 pm, David Kastrup wrote: > > >> %%%% > > >> \version "2.22.0" > > >> SvgAddClassName = > > >> #(lambda (ctxt) > > >> (define (add-class-name grob) > > >> (let* ((attribs (ly:grob-property grob 'output-attributes '())) > > >> (class (ly:assoc-get 'class attribs '())) > > >> (name (grob::name grob))) > > >> (set! class (if (null? class) name (format #f "~a ~a" class > > >> name))) > > >> (set! attribs (assoc-set! attribs 'class class)) > > >> (ly:grob-set-property! grob 'output-attributes attribs))) > > >> (make-engraver > > >> (acknowledgers > > >> ((grob-interface engraver grob source) > > >> (add-class-name grob))))) > > > That assoc-set! looks like a stinker. Doesn't it mess with shared > > > data > > > structures? > > Hrm... would it be better to explicitly alist-copy the result from > > ly:assoc-get? Actually, I guess you could do: > > ;;;; > > (alist-cons 'class ... (alist-delete 'class attribs)) > > ;;;; > Either that or not even bother about deleting the other entry. > > > ...since the SRFI says that alist-delete does not modify the original > > structure, only that it might return an alist with a common tail. > > And on this point, should LilyPond provide an ly:assoc-set to pair > > with ly:assoc-get that avoids potential issues with shared structures? > I am not sure that we'd want our own modifiers for basic data > structures. Though there may be a point in unifying hash tables, > association lists, vectors into a common data structure and provide > caching accessors for that. > > I mean, stuff like notename languages and drum tables and so are already > an awkward mixture.
My single biggest annoyance and hair pulling source with Guile is its lack of good data structures. We use alists almost ubiquitously, going against all rules of computational complexity, but hash tables are much less convenient to create for a user, and much more complicated to work on with all standard functional primitives like map, filter, filter-map, fold, reduce, partition, etc. etc. etc. (they might also be less memory-efficient if I recall correctly). The use of alists is pervasive enough that switching to better structures might yield speedups. For example, a different storage for prob and grob properties (I think you had something based on vectors at some point?). There is a similar hiatus between arrays of grobs and lists of grobs due to the differing programming styles in C++ and Scheme. Recent Guile has something called "VLists" that could help here: https://www.gnu.org/software/guile/manual/html_node/VLists.html I have no idea about the extent to which this could match our use cases. The implementation is Scheme-only, and it would be ironic if switching to algorithms with better complexity led to a performance degradation (see the caveat about vlist-cons in the documentation page). To address Aaron's question more specifically and with shorter-term perspectives, one could add a Scheme interface for nested_property_alist in nested-property.cc (I *think* it has no side effects, too late to check today). It wouldn't exactly match this case, however: attrs = #'((name . NAME) (class . CLASS) (whatever . WHATEVER)) #(define (printit grob) (ly:message "~a" (ly:grob-property grob 'output-attributes))) { \override NoteHead.output-attributes = #attrs \override NoteHead.output-attributes.class = #'NEWCLASS \override NoteHead.after-line-breaking = #printit c } We might be able to make it set the value, though (again, I'm not looking hard at the code). That being said, I'm not sure I would want to see something along the lines of publicizing nested_property_alist. We already use ly:assoc-get nearly everywhere (through the alias assoc-get), and while more convenient thanks to the optional default value parameter, it is not as efficient as assq-ref when, as is often the case, the keys are symbols, which can be cheaply compared with eq?. My concern is that code may then be written that copies the data n times if doing n insertions instead of just working on a copy made once. So this would warrant some thinking and perhaps a structure of our own. The challenge will be in trying to make it work more or less seamlessly with standard Guile libraries. My 2 cents, Jean