Hello David,

> Neither surprising nor an edge case.

I would say it is quite surprising for most users, and definitely an edge case. 
It is essentially a case of `\applyContext` silently behaving differently when 
the Voice context was not created yet. And even you are getting this wrong: 

> That's because at the point of the first call, you haven't yet descended
> into a Voice or even Staff context from the surrounding Score context.
> So \applyContext prints the Stem.length setting for the Score context
> which has not been changed (you only changed the default for every
> bottom context).
> 
> If you want to override Stem.length at the Score level, either write
> 
> \override Score.Stem.length = ...
> 
> in your \layout block, or write things like described in the docs,
> namely
> 
> \layout {
>   \context {
>     \Score
>     \override Stem.length = ...
>   }
> }

This creates the same output, because the top context is not Score, but 
Global. At the point in question not even a score context exists, so this is 
called in the global context. This we can also see when doing

```
testfn =
#(lambda (context)
   (display context)
   (newline))

\score {
  {
    \applyContext #testfn
    4
    \applyContext #testfn
  }
}
```

which will display

> #<Global_context Global () >
> #<Context Voice () >

So actually you’d have to do

```\override Global.Stem.length = #0```

or

```\context { \Global ... }```

This makes me wonder one more time if `\applyContext` should take an optional 
context argument, allowing to specify which context this should run on, and 
fail if this context is not found, such as in this mockup:

```
myApplyContext =
#(define-music-function (name id proc)
   ((symbol? #f) (string? #f) procedure?)
   (define (context-find name id ctx)
     (and
      ctx
      (if (and (equal? (ly:context-name ctx) name)
               (or (not id) (equal? (ly:context-id ctx) id)))
          ctx
          (context-find name id (ly:context-parent ctx)))))
   (applyContext
    (if name
        (lambda (ctx)
          (let ((context (context-find name id ctx)))
            (if context
                (proc context)
                (ly:warning-located
                 (apply format #f "~a:~a:~a:~a" (ly:input-file-line-char-column 
(*location*)))
                 "Context ~a not found"
                 (if id (format #f "~a = ~a" name id) name)))))
        proc)))

testfn =
#(lambda (context)
   (display context)
   (display ", ")
   (display (ly:context-name context))
   (display ", ")
   (display (ly:context-id context))
   (newline))

{ \myApplyContext #testfn 4 \myApplyContext #testfn 4 \myApplyContext Global 
#testfn }

\new StaffGroup = "outer" \new StaffGroup = "inner" \new Staff
{ s4 \myApplyContext StaffGroup #testfn s4 \myApplyContext StaffGroup "outer" 
#testfn }
```

which would in the given case

```
displayStemLength =
#(lambda (context)
   (let* ((grob-def (ly:context-grob-definition context 'Stem))
          (length (ly:assoc-get 'length grob-def)))
     (display "+ ")
     (display length)
     (newline)))

\score {
  \relative c'' {
    \myApplyContext Voice #displayStemLength
    g4
    \myApplyContext Voice #displayStemLength
    g
  }
  \layout {
    \override Stem.length = #0
  }
}
```

issue a warning for the first call

> [location]: Warning: Context Voice not found

Cheers,
Valentin

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to