10.18.3 Music functions and Guile debugging

Ian Hulin was trying to do some debugging in music functions, and came up with the following question (edited and adapted to current versions):

HI all, I’m working on the Guile Debugger Stuff, and would like to try debugging a music function definition such as:

conditionalMark =
#(define-music-function () ()
  #{ \tag instrumental-part {\mark \default} #} )

It appears conditionalMark does not get set up as an equivalent of a Scheme

(define conditionalMark = define-music-function () () ...

although something gets defined because Scheme apparently recognizes

#(set-break! conditionalMark)

later on in the file without signalling any Guile errors.

However the breakpoint trap is never encountered as define-music-function passed things on to ly:make-music-function, which is really C++ code ly_make_music_function, so Guile never finds out about the breakpoint.

The answer in the mailing list archive at that time was less than helpful. The question already misidentifies the purpose of ly:make-music-function which is only called once at the time of defining conditionalMark but is not involved in its later execution.

Here is the real deal:

A music function is not the same as a Guile function. It boxes both a proper Scheme function (with argument list and body from the define-music-function definition) along with a call signature representing the types of both function and arguments.

Those components can be reextracted using ly:music-function-extract and ly:music-function-signature, respectively.

When LilyPond’s parser encounters a music function call in its input, it reads, interprets, and verifies the arguments individually according to the call signature and then calls the proper Scheme function.

While it is actually possible these days to call a music function as if it were a Scheme function itself, this pseudo-call uses its own wrapping code matching the argument list as a whole to the call signature, substituting omitted optional arguments with defaults and verifying the result type.

So putting a breakpoint on the music function itself will still not help with debugging uses of the function using LilyPond syntax.

However, either calling mechanism ultimately calls the proper Scheme function stored as part of the music function, and that is where the breakpoint belongs:

#(set-break! (ly:music-function-extract conditionalMark))

will work for either calling mechanism.

LilyPond Contributor’s Guide v2.25.17 (development-branch).