"Pure" calls in the LilyPond backend produce grob properties dependent on line break decisions. Consequently the calls get passed "start" and "end" arguments denoting the current line's starting and ending musical columns (numbered sequentially from the start of the score).
To make the calls more compatible, in a first step the arguments start/end should get removed. They can be instead passed as a "parameter" in the dynamic scope and queried by calling (*start*) and (*end*) calls (which is the typical lexical convention for accessing parameters passed implicitly). This is a refactoring that does not change anything conceptually: it is just somewhat tedious word. The second iteration then becomes a lot more tricky: pure and unpure calls are no longer distinguished explictly. Instead, the calls of (*start*) and (*end*) itself record which properties (most importantly stencils) queried the respective break columns in the course of generating their value and will use the pure caching mechanism only for those. That allows no longer separating the two. This is particularly useful if a property only depends on one of the break columns, or needs to refer to them only in isolated cases. Being able to forego pure treatments when not necessary has a potential for saving quite some runtime. Of course, for imprudently written callbacks, it also has the potential to blow up runtime in return for treating the dependencies correctly. One consequence of figuring out the pure/unpure stuff automagically would be that programming callbacks would become more straightforward and look less like an arcane art. Which is a good thing. Throwing this out in the open as a project because right now I am in a tricky personal situation where I'll not likely be able to work on it myself for a while. In addition, part 1 is mostly grunge work touching a lot of stuff in pretty mechanical ways, the stuff I am comparatively bad at completing in a sensible time frame. The most involved part here is getting backward compatibility and convert-ly sorted out. It would probably make sense to retain ly:make-unpure-pure-container with the same semantics and calling conventions but stop using it in our code base, instead using ly:make-unpure-pure-container-1 (for the 1-argument version of the call). Part 2 is where the magic lies. Having completed part 1, part 2 would become more accessible for analyzing and tackling. With (*start*)/(*end*) only being accessed when really necessary, the amount of code needing touching would not be distributed all over the place. So changing the semantics would not involve code lines all over the place and could possibly done in several phases. How do we enter such a multi-phase project in the issue tracker? -- David Kastrup
