PATCHES - Countdown to April 24th

2022-04-22 Thread Colin Campbell

Here is the current countdown list.

The next countdown will be on April 24th.

A list of all merge requests can be found here:
https://gitlab.com/lilypond/lilypond/-/merge_requests?sort=label_priority


 Push:

!1317 Fix and improve formatting of Scheme signatures in IR - Jean Abou 
Samra

https://gitlab.com/lilypond/lilypond/-/merge_requests/1317

!1315 Improve (and run) fixscm.sh - Jean Abou Samra
https://gitlab.com/lilypond/lilypond/-/merge_requests/1315

!1313 relocate: Try looking through symlinks - Jonas Hahnfeld
https://gitlab.com/lilypond/lilypond/-/merge_requests/1313

!1312 Improve build messages - Werner Lemberg
https://gitlab.com/lilypond/lilypond/-/merge_requests/1312


 Countdown:

!1320 Doc: use HTTPS throughout - Jean Abou Samra
https://gitlab.com/lilypond/lilypond/-/merge_requests/1320

!1319 Doc-CG: revise 'Further Git documentation resources' - Jean Abou Samra
https://gitlab.com/lilypond/lilypond/-/merge_requests/1319

!1318 Grob::internal_get_object: remove a check for unpure/pure 
containers - Jean Abou Samra

https://gitlab.com/lilypond/lilypond/-/merge_requests/1318

!1316 Vim: set undo_ftplugin and undo_indent variables - Doug Kearns
https://gitlab.com/lilypond/lilypond/-/merge_requests/1316


 Review:

!1321 Fix DurationLine thickness for different staff sizes - Thomas Morley
https://gitlab.com/lilypond/lilypond/-/merge_requests/1321

!1314 breathMarkType - Dan Eble
https://gitlab.com/lilypond/lilypond/-/merge_requests/1314


 New:

No patches in New at this time.


 Waiting:

!1136 \break implies \bar "" when needed - Dan Eble
https://gitlab.com/lilypond/lilypond/-/merge_requests/1136

!913 release: binaries with cairo - Han-Wen Nienhuys
https://gitlab.com/lilypond/lilypond/-/merge_requests/913

Cheers,

Colin




Re: C++ question on wrapper API for setting Guile fluids

2022-04-22 Thread Dan Eble
On Apr 22, 2022, at 05:39, Jean Abou Samra  wrote:
> 
> You both made a good point. My conclusion is that I should stick to
> 
>   {
> Local_assumption la (Lily::prebreak_estimate, SCM_BOOL_T);
> ...
>   }
> 
> where the constructor does everything, included scm_dynwind_begin ()
> and scm_dynwind_fluid (). That's safer and clearer, and never mind that
> you have to construct 3 contexts if you need 3 assumptions. I expect
> this to be very rare anyway.

Fine.  At the time someone wants more than one assumption, we might be able to 
add

Local_assumptions la {{fluid1, value1},
^ {fluid2, value2} /* etc. */ };

where the constructor accepts std::initializer_list> but 
I don't know if there are any problems related to GC (and I'm not planning to 
work through that now).
— 
Dan




Re: Missing dependencies in doc build after addition of PDF syntax highlighting?

2022-04-22 Thread Jean Abou Samra

Le 21/04/2022 à 09:31, Jonas Hahnfeld a écrit :

This says "to rebuild only 'contributor.pdf'", which should still work
fine in an incremental build, no?



Granted. The first of the two occurrences on that page
does not imply that the full documentation build should
be done first, though.

Jean



Re: C++ question on wrapper API for setting Guile fluids

2022-04-22 Thread David Kastrup
Jean Abou Samra  writes:

> Re call/cc: I would actually like to use
> static_cast (0)
> and not SCM_F_WIND_EXPLICITLY. I have no idea whether the stuff I write
> is going to interact gracefully with rewinding the stack via continuations,
> and I honestly don't want to wonder.We're using C++ (on contrary to Guile,
> which is primarily tailored for C), so most allocations (e.g., vectors) are
> managed via C++ RAII. This means that C++'s stack unwinding and
> Guile's don't
> interact, so you can easily crash LilyPond with continuations and
> such, by making
> some expression return twice and arranging for it to cause double free. This
> is the first example that came to my mind:
>
> \version "2.23.7"
>
> {
>   \override NoteHead.X-extent =
>     #(let ((cont #f))
>    (lambda (grob)
>  (if cont
>  (cont '(0 . 0))
>  (call/cc
>   (lambda (c)
>     (set! cont c)
>     '(0 . 0))
>   c d
> }
>
>
>
> Frankly, I don't think we need to bother at all about such stuff. If
> the user is willing this hard to shoot themselves in the foot, we
> can't prevent them.

It's worth keeping in mind that dynamic programming (like trying to
figure out the best breakpoint sequence) naturally lends itself to
juggling a set of best continuations so far (a continuation is more
versatile to build upon than a static description of a partial
solution).

But the main control flow strategies are certainly maintained by
LilyPond itself, so we are mainly shooting ourselves in the foot by
blocking certain programming practices that make your head ache but may
actually be a good fit for "under the hood".  So it's stuff that there
is no point in bending over backwards to get right, but if we see a
reasonably easy and affordable way to do it "continuation-safe", it's
probably worth doing it and thus keeping more options easily accessible
for the future.

One example of "weird control flow" I had to revert to is
map-markup-commands even if it does not go to the depths of restarting
continuations but "only" throws parts of a solution.

-- 
David Kastrup



Re: C++ question on wrapper API for setting Guile fluids

2022-04-22 Thread Jean Abou Samra

Le 22/04/2022 à 09:52, Luca Fascione a écrit :

[snipped]
Where the problem is that dwc.free(p) is actually effectively acting 
as if it was dwc2.free(p); because the API doesn't pass around the 
context like the C++ wrappers appear to do, rather it statefully "just 
goes for it".
This is a design decision of Guile, obviously. However, it seems to me 
this has possibly uncommon semantics even if it were implemented on 
the scheme-language side of things anyways, doesn't it? I guess I'm 
asking whether people would want/need to do this on purpose, and why. 
It seems to me to achieve this behaviour one would have to capture the 
dwc context and then invoke dwc.free() on that context from deeper 
inside its own stack, and I'm not clear what this means for the frames 
intervening inbetween the calling frame and the callee frame, being a 
current parent of it, maybe it's ok, I normally think of continuations 
as things to deal with a stack that has been unwound, not deeper parts 
of a stack that is still being executed.




I guess it would be possible to make it work, using 
scm_current_dynamic_state
and scm_set_current_dynamic_state. I don't have a need to implement it, 
though.
Assumptions should always be introduced just after creating the dynamic 
context.




[...]

I think the first observation is very good: making it easiest to spot 
wrong code without paying large amounts of attention has been a very 
good strategy for me in the past.
And for the same reason, assuming the scm_dynwind_XXX set of calls is 
small, I would either wrap all of them (because they're all small and 
easy) or very clearly document the wrapper class as "if you need this 
method, add it here and this is how": you definitely don't want to 
find yourself in a halfway house where there are all sorts of 
exceptions that "yes these three methods could have been wrapped but 
we didn't" and now nobody remembers any longer why a decision was 
taken one way or the other. It's a small cost now and can save many 
headaches later.
Obv this works if the set of scm_dynwind_XXX is small (maybe up to 
10-15 calls?), if you have several dozens, you'd definitely wrap a few 
important ones that you need, and leave the rest for another day (with 
the comment inviting the next person along to help with the effort).






You both made a good point. My conclusion is that I should stick to

  {
    Local_assumption la (Lily::prebreak_estimate, SCM_BOOL_T);
    ...
  }

where the constructor does everything, included scm_dynwind_begin ()
and scm_dynwind_fluid (). That's safer and clearer, and never mind that
you have to construct 3 contexts if you need 3 assumptions. I expect
this to be very rare anyway.



As to the exchange Jean and I were having about non-local control 
flow, I was worried about scm_dynwind_end() being called one extra 
time (rather than not being called enough, as your example 
demonstrates) and how to detect that, but looking at how 
scm_dynamic_wind() is implemented, maybe from the C side this can't 
happen. I'm asking: is there a case where evaluating the "main", 
non-guard thunk implies a call to scm_dynwind_end(), so that the outer 
C code doesn't need to? And I think the answer to that is no. So I 
guess as long as we can guarantee that the think doesn't use call/cc 
(or that we always use SCM_F_DYNSTACK_FRAME_REWINDABLE) this will be ok?




Re "can scm_dynwind_end () be called unpaired in the thunk": if the callee
respects programming contracts, no. The principle of scm_dynwind_begin 
() and
scm_dynwind_end () is that they should always be paired under normal 
circumstances

(when no Guile non-local control flow happens).

Re call/cc: I would actually like to use 
static_cast (0)

and not SCM_F_WIND_EXPLICITLY. I have no idea whether the stuff I write
is going to interact gracefully with rewinding the stack via continuations,
and I honestly don't want to wonder.We're using C++ (on contrary to Guile,
which is primarily tailored for C), so most allocations (e.g., vectors) are
managed via C++ RAII. This means that C++'s stack unwinding and Guile's 
don't
interact, so you can easily crash LilyPond with continuations and such, 
by making

some expression return twice and arranging for it to cause double free. This
is the first example that came to my mind:

\version "2.23.7"

{
  \override NoteHead.X-extent =
    #(let ((cont #f))
   (lambda (grob)
 (if cont
 (cont '(0 . 0))
 (call/cc
  (lambda (c)
    (set! cont c)
    '(0 . 0))
  c d
}



Frankly, I don't think we need to bother at all about such stuff. If the 
user

is willing this hard to shoot themselves in the foot, we can't prevent them.

Echoing Han-Wen's fear about the problems linked with dynamic states, 
the reason
to use fluids, apart from consistency with the existing (*parser*) and 
(*location*),

is to be a little cooperative with basic and actually useful non-local flow
such as (mock 

Re: C++ question on wrapper API for setting Guile fluids

2022-04-22 Thread Luca Fascione
On Thu, Apr 21, 2022 at 11:46 PM Jean Abou Samra  wrote:

> Well, the C++ and Scheme interfaces can feel different and idiomatic
> in their respective languages as long as they share the same
> underlying implementation.
>

I think this is a super important goal. In fact, I'd upgrade 'can' to
'should' :-)


> In the same vein, although Guile has scm_dynamic_wind (), the
> recommended C interface is scm_dynwind_begin () / scm_dynwind_end ()
> because that is more scalable in C code.
>

Yes, and that supports your idea of using RAII to bookend it correctly in
the face of exceptions and such things.
Which is very idiomatic in modern C++ and feels quite natural to me.

Dan had an objection about this case:

{
  Dynwind_context dwc;
  // . . .

  {
Dynwind_context dwc2;
// . . .
dwc.free (p);  // not what it seems
// . . .
  }
}

Where the problem is that dwc.free(p) is actually effectively acting as if
it was dwc2.free(p); because the API doesn't pass around the context like
the C++ wrappers appear to do, rather it statefully "just goes for it".
This is a design decision of Guile, obviously. However, it seems to me this
has possibly uncommon semantics even if it were implemented on the
scheme-language side of things anyways, doesn't it? I guess I'm asking
whether people would want/need to do this on purpose, and why. It seems to
me to achieve this behaviour one would have to capture the dwc context and
then invoke dwc.free() on that context from deeper inside its own stack,
and I'm not clear what this means for the frames intervening inbetween the
calling frame and the callee frame, being a current parent of it, maybe
it's ok, I normally think of continuations as things to deal with a stack
that has been unwound, not deeper parts of a stack that is still being
executed. Whereas in a way this is what {} scoping does, it's weird that
there could be intervening function calls and this would still be allowed,
because this second scenario is closer to implementing TCL's upvar/uplevel
mechanism, which I've learned Schemers really don't like. For these reasons
I suspect that Dan's example can easily happen by mistake, but wouldn't be
something that folks have a legitimate, every-day use for, or is it?

Anyways I was reading the source of Guile from the repo, and I found that
dynwind_begin() does this:

void
scm_dynwind_begin (scm_t_dynwind_flags flags)
{
  scm_thread *thread = SCM_I_CURRENT_THREAD;
  scm_dynstack_push_frame (>dynstack, flags);
}


So I'm thinking that (maybe in some appropriate debug mode) if
Dynwind_context were to capture a copy of >dynstack, it could then
check if the stack has moved or not,
and error out in some useful way if the (dyn)stack pointer has changed.
Given C++ semantics, I suspect it can only change by being deeper, but one
way or the other, this could work.
Mind you, as much as the proposed RAII idea is kinda slightly dangerous, I
don't think we should protect too much for folks doing irresponsible things
with the stack, as long as
the documentation is clear about how the wrapper works, this should be
fine.

On the other hand, if this concept of messing with dwc from a stack frame
deeper inside is important, dynstack.h has all controls for capturing and
standing up local stacks, so one could instead do a full capture in the
constructor (say calling scm_dynstack_capture_all, or something like that)
to allow for this behaviour (and then the forwarding methods would adjust
the dynstack to always be pointed as expected).
It seems a bit overkill to me, because I'm not used to the semantics
implied by doing this, but all the same it appears this might work.

-> footnote: these arguably all appear to be internal API entrypoints, I'm
not sure what this means in terms of it being a polite thing or not to call
them from lilypond's codebase.

Earlier in the thread Jean said:

> Making a method of the context is an attractive proposal, as
> it prevents from forgetting to introduce a context.
>
> Actually, the specific use case is much narrower than this particular
> set of methods: I don't need C++ wrappers for all dynwind-related Guile
> APIs, I just have one need for fluids. The example in the first email was
> a straw man for the sake of explanation.

I think the first observation is very good: making it easiest to spot wrong
code without paying large amounts of attention has been a very good
strategy for me in the past.
And for the same reason, assuming the scm_dynwind_XXX set of calls is
small, I would either wrap all of them (because they're all small and easy)
or very clearly document the wrapper class as "if you need this method, add
it here and this is how": you definitely don't want to find yourself in a
halfway house where there are all sorts of exceptions that "yes these three
methods could have been wrapped but we didn't" and now nobody remembers any
longer why a decision was taken one way or the other. It's a small cost now