5.5.6 Unpure-pure containers

Unpure-pure containers are useful for overriding Y-axis spacing
calculations - specifically Y-offset and Y-extent - with a
Scheme function instead of a literal (i.e., a number or pair).

For certain grobs, the Y-extent is based on the stencil
property, overriding the stencil property of one of these will
require an additional Y-extent override with an unpure-pure
container. When a function overrides a Y-offset and/or
Y-extent it is assumed that this will trigger line breaking
calculations too early during compilation. So the function is not
evaluated at all (usually returning a value of ‘0’ or
‘'(0 . 0)’) which can result in collisions. A ‘pure’ function
will not affect properties, objects or grob suicides and therefore will
always have its Y-axis-related evaluated correctly.

Currently, there are about thirty functions that are already considered
‘pure’ and Unpure-pure containers are a way to set functions not on
this list as ‘pure’. The ‘pure’ function is evaluated before
any line-breaking and so the horizontal spacing can be adjusted
‘in time’. The ‘unpure’ function is then evaluated after
line breaking.

Note: As it is difficult to always know which functions are on this
list we recommend that any ‘pure’ functions you create do not use
Beam or VerticalAlignment grobs.

An unpure-pure container is constructed as follows;

(ly:make-unpure-pure-container f0 f1)

where f0 is a function taking n arguments (n >= 1)
and the first argument must always be the grob. This is the function
that gives the actual result. f1 is the function being labeled
as ‘pure’ that takes n + 2 arguments. Again, the first argument
must always still be the grob but the second and third are ‘start’
and ‘end’ arguments.

start and end are, for all intents and purposes, dummy
values that only matter for Spanners (i.e Hairpin or
Beam), that can return different height estimations based on a
starting and ending column.

The rest are the other arguments to the first function (which
may be none if n = 1).

The results of the second function are used as an approximation of the
value needed which is then used by the first function to get the real
value which is then used for fine-tuning much later during the spacing
process.

In the first measure, without the unpure-pure container, the spacing
engine does not know the width of the note head and lets it collide with
the accidentals. In the second measure, with unpure-pure containers,
the spacing engine knows the width of the note heads and avoids the
collision by lengthening the line accordingly.

Usually for simple calculations nearly-identical functions for
both the ‘unpure’ and ‘pure’ parts can be used, by only
changing the number of arguments passed to, and the scope of, the
function. This use case is frequent enough that
ly:make-unpure-pure-container constructs such a second
function by default when called with only one function argument.

Note: If a function is labeled as ‘pure’ and it turns out not to
be, the results can be unexpected.