Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 23:35, David Kastrup a écrit : Properties will be coded a lot in Scheme. So the interface needs to map naturally to Scheme programming. Well, the C++ and Scheme interfaces can feel different and idiomatic in their respective languages as long as they share the same underlying implementation. 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.
Re: C++ question on wrapper API for setting Guile fluids
Jean Abou Samra writes: > Le 21/04/2022 à 13:10, Dan Eble a écrit : >> That is probably mostly due to your early remark that your >> control-flow options are limited in the case of a with_fluid wrapper >> taking a lambda. (It definitely steered my answer.) > > > Well, I find it better if it doesn't require reworking the control > flow logic to introduce assumptions in existing code. Also, that > should facilitate the refactoring of unpure/pure containers into > assumptions. Properties will be coded a lot in Scheme. So the interface needs to map naturally to Scheme programming. -- David Kastrup
Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 13:10, Dan Eble a écrit : That is probably mostly due to your early remark that your control-flow options are limited in the case of a with_fluid wrapper taking a lambda. (It definitely steered my answer.) Well, I find it better if it doesn't require reworking the control flow logic to introduce assumptions in existing code. Also, that should facilitate the refactoring of unpure/pure containers into assumptions.
Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 12:58, David Kastrup a écrit : My personal take on this would move the magic out of the normal reach of users. You get (*start-column*) and (*end-column*) which you can use for accessing the respective fluids but the function *start-column* does not merely access %start-column but it also registers the associated impurity for the sake of caching. Absolutely, I don't want to make the fluids accessible to anything outside of the property infrastructure. *start-column* (or whatever name) is an Assumption object. Assumption is a smob type defining a call () smob procedure. That way, you can have (*start-column*) and (under-assumptions ((*start-column* 0)) ...) and both of these use the fluid as well as other internal members of the assumption without ever making them accessible. For the latter, the under-assumptions macro invocation translates to (ly:run-under-assumption *start-column* 0 (lambda () ...)) which makes the interface completely opaque/encapsulated.
Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 11:18, Han-Wen Nienhuys a écrit : OK. I'm curious to see how that turns out. I am too :-) I've been intermittently working on this project for more than 6 months now. When I do an experimental refactoring, I make a new branch from the current one to avoid losing the previous work. Currently I am working in a branch called 'purity5' ... Does every call to get_property() will have to check the fluid as well to see if it should cache the computed value? Yes. I'm trying to make it such that this check is fast, because get_property without purity at all is the frequent case. How does the caching framework know if the computation depends on the assumption? In my current design, Output_def gains a new member, which is a stack (SCM list). Each element of the stack corresponds to a property callback that is currently being made. The element is a list of assumptions that have been used for this call. Suppose, for example, that you have the call chain VerticalAxisGroup.adjacent-pure-heights [introduces *prebreak-estimate*, *prebreak-estimate-start*, *prebreak-estimate-end*] -> PaperColumn.Y-extent -> NoteColumn.Y-extent -> Stem.Y-extent Each get_property call pushes a frame on the Output_def's stack. During the Stem.Y-extent callback, the stack looks like (() ;; Stem.Y-extent () ;; NoteColumn.Y-extent () ;; PaperColumn.Y-extent () ;; VerticalAxisGroup.adjacent-pure-heights ...) Moreover, when the *prebreak-estimate* assumption is introduced, it records the state of the stack. So *prebreak-estimate* remembers the SCM sublist that corresponds to the part (() ;; VerticalAxisGroup.adjacent-pure-heights ...) (Equivalently, it could also remember the stack's depth.) Now, Stem.Y-extent accesses *prebreak-estimate*. This records in the stack that callbacks inside the scope where the assumption has been introduced need to get special caching. More precisely, the stack is walked until the sublist recorded by *prebreak-estimate* is found. This makes it look like ((#) ;; Stem.Y-extent (#) ;; NoteColumn.Y-extent (#) ;; PaperColumn.Y-extent () ;; VerticalAxisGroup.adjacent-pure-heights ...) At the end of the Stem.Y-extent get_property () call, the top frame is popped off and checked. If it's '(), the property can be cached normally. If it's a 1-element list containing *prebreak-estimate*, it receives caching with a prebreak value and a postbreak value. Anything else leads to no caching at all. (Except if benchmarks tell that it brings a performance advantage to cache according to (start, end) in a hash table.)
Re: C++ question on wrapper API for setting Guile fluids
On Apr 21, 2022, at 06:54, Jean Abou Samra wrote: > > Le 21/04/2022 à 12:47, David Kastrup a écrit : >> So what one would want is a C++ wrapper working with functionals? ... > So this needs an interface that is easier to use, whether it uses > RAII or functionals or something else. Current talks in this thread > favor the RAII approach. That is probably mostly due to your early remark that your control-flow options are limited in the case of a with_fluid wrapper taking a lambda. (It definitely steered my answer.) — Dan
Re: C++ question on wrapper API for setting Guile fluids
Jean Abou Samra writes: > Le 21/04/2022 à 10:38, Han-Wen Nienhuys a écrit : >> On Thu, Apr 21, 2022 at 12:04 AM Jean Abou Samra wrote: >>> I am working on code that pervasively utilizes Guile fluids. They should >>> be set in dynamic scopes. >> That sounds scary. Care to tell more? > > What is scary about it exactly? > > I am trying to reimplement purity in terms of fluids, so the set of > parameters is not hardcoded to 'start, end' and all the code doesn't > have to be littered with functions working both as pure and impure and > forwarding start/end to the property callbacks they > cause. Good. > Essentially, this should look like { Dynwind_context dwc; > dwc->make_assumption (Lily::prebreak_estimate, SCM_BOOL_T); > ... get_property (grob, "property") ... } or in Scheme: > (under-assumptions ((*prebreak-estimate* #t)) ...) and by virtue of > the dynamic context, the callback that computes the grob property > understands that it should do pure estimates. My personal take on this would move the magic out of the normal reach of users. You get (*start-column*) and (*end-column*) which you can use for accessing the respective fluids but the function *start-column* does not merely access %start-column but it also registers the associated impurity for the sake of caching. This also helps by not registering impurities that don't arise for a particular grob (things like breakpoint-depending accidentals comparatively rarely rise to the level of actual relevance but get everything dealt with as impure, with the associated costs, all the time). > I haven't gotten as far as a working proof of concept, but I expect a > speedup. This is essentially a remix of an idea from David: > https://lists.gnu.org/archive/html/lilypond-devel/2015-05/msg00397.html I probably repeat myself... -- David Kastrup
Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 12:47, David Kastrup a écrit : So what one would want is a C++ wrapper working with functionals? My criterion is rather convenience. scm_c_with_fluid could be convenient if I could use it with a lambda. However, I cannot, I'd need to define a separate function every time, taking void * and casting that to some struct where needed local variables are stored. For repeated use, that is a nuisance. So this needs an interface that is easier to use, whether it uses RAII or functionals or something else. Current talks in this thread favor the RAII approach.
Re: C++ question on wrapper API for setting Guile fluids
I wonder if you can 'chain' them: Dynwind_context dwc2(dwc); (you can at a minimum 'pause' dwc so to emit a runtime message that the "wrong" thing is happening, but I guess you could hand yourself to your parent and do more sophisticated shenanigans too... I must say I loathe this stateful stuff though) L On Thu, Apr 21, 2022 at 12:23 PM Dan Eble wrote: > On Apr 21, 2022, at 02:55, Luca Fascione wrote: > > > > I'd think you can up this by one, and get a cleaner looking piece of code > > if you implement scm_dynwind_fluid() as a forwarded method on your > context: > ... > > dwc.fluid (fluid2, value2); > > Here's something that does bother me. That reads as if dwc holds state > affecting the outcome, which is untrue. > > { > Dynwind_context dwc; > // . . . > > { > Dynwind_context dwc2; > // . . . > dwc.free (p); // not what it seems > // . . . > } > } > > The scm_ functions operate implicitly on the current context. Dressing > them differently would be confusing. > — > Dan > > -- Luca Fascione Distinguished Engineer - Ray Tracing - NVIDIA
Re: C++ question on wrapper API for setting Guile fluids
Jean Abou Samra writes: >> Le 21/04/2022 11:05, David Kastrup a écrit : >> Just for the record, your usage would not fit with the existing >> lily/include/fluid.hh , > > > The existing code in fluid.hh is concerned with retrieving > fluids. I'm asking about setting them. Whether the new code > can go in fluid.hh is a question, but it is new code. > > >> and scm_c_with_fluid does not suffice? > > > It would suffice, but it does not work with C++ lambdas, > which makes it inconvenient. So what one would want is a C++ wrapper working with functionals? -- David Kastrup
Re: C++ question on wrapper API for setting Guile fluids
On Apr 21, 2022, at 02:55, Luca Fascione wrote: > > I'd think you can up this by one, and get a cleaner looking piece of code > if you implement scm_dynwind_fluid() as a forwarded method on your context: ... > dwc.fluid (fluid2, value2); Here's something that does bother me. That reads as if dwc holds state affecting the outcome, which is untrue. { Dynwind_context dwc; // . . . { Dynwind_context dwc2; // . . . dwc.free (p); // not what it seems // . . . } } The scm_ functions operate implicitly on the current context. Dressing them differently would be confusing. — Dan
Re: C++ question on wrapper API for setting Guile fluids
Not sure why my message got mangled? Resending, properly formatted. Le 21/04/2022 à 10:51, Jean Abou Samra a écrit : Le 21/04/2022 à 10:38, Han-Wen Nienhuys a écrit : On Thu, Apr 21, 2022 at 12:04 AM Jean Abou Samra wrote: I am working on code that pervasively utilizes Guile fluids. They should be set in dynamic scopes. That sounds scary. Care to tell more? What is scary about it exactly? I am trying to reimplement purity in terms of fluids, so the set of parameters is not hardcoded to 'start, end' and all the code doesn't have to be littered with functions working both as pure and impure and forwarding start/end to the property callbacks they cause. Essentially, this should look like { Dynwind_context dwc; dwc->make_assumption (Lily::prebreak_estimate, SCM_BOOL_T); ... get_property (grob, "property") ... } or in Scheme: (under-assumptions ((*prebreak-estimate* #t)) ...) and by virtue of the dynamic context, the callback that computes the grob property understands that it should do pure estimates. The property then gets cached if it doesn't depend on assumptions, or if it only depends on *prebreak-estimate* (in that case with two cached value, prebreak and postbreak), but not if the callback uses *prebreak-estimate-start* or *prebreak-estimate-end*. I'll have to experiment with caching strategies, but this is the current idea. The advantage is that 95% of code that needs to interact with purity (via ly:make-unpure-pure-container, get_maybe_pure_property, etc.) no longer needs to do so. Purity becomes a very localized thing and no longer pervades the code base. It can also be worked on more easily; my work on https://gitlab.com/lilypond/lilypond/-/merge_requests/744 involves introducing pure widths, and I don't want to add maybe_pure_x_extent and change hundreds of callbacks so they do maybe_pure_x_extent instead of extent ( X_AXIS). There is the same need in order to properly implement functionality demonstrated in a recent -user thread https://lists.gnu.org/archive/html/lilypond-user/2022-04/msg00062.html where LyricText.X-offset needs a pure/unpure distinction in order to avoid after-line-breaking. Also, since whether callbacks access start and end is now known, pure properties that depend on whether the call is pure or not but not on start and end (namely the vast majority of them) can start getting cached. Right now, we use a trick to cache item pure heights, assuming that Y-extent/Y-offset does not depend on start/end for items (Item::pure_y_extent). This can then be done for spanners as well. I haven't gotten as far as a working proof of concept, but I expect a speedup. This is essentially a remix of an idea from David: https://lists.gnu.org/archive/html/lilypond-devel/2015-05/msg00397.html Jean
Re: C++ question on wrapper API for setting Guile fluids
On Thu, Apr 21, 2022 at 10:53 AM Jean Abou Samra wrote: > >> On Thu, Apr 21, 2022 at 12:04 AM Jean Abou Samra > >> wrote: > >>> I am working on code that pervasively utilizes Guile fluids. They > >>> should > >>> be set in dynamic scopes. > >> That sounds scary. Care to tell more? > > > > What is scary about it exactly? I am worried about introducing problems associated with dynamic scoping into the code base; the (un)pure stuff is already there though, so it probably is not going to create new problems, though. > I am trying to reimplement purity in terms of fluids, so the set of > parameters is not hardcoded to 'start, end' and all the code doesn't > have to be littered with functions working both as pure and impure and > forwarding start/end to the property callbacks they > cause. Essentially, this should look like > > > { >Dynwind_context dwc; >dwc->make_assumption (Lily::prebreak_estimate, SCM_BOOL_T); >... get_property (grob, "property") ... > } > > or in Scheme: > > (under-assumptions ((*prebreak-estimate* #t)) >...) > > and by virtue of the dynamic context, the callback that computes the > grob property understands that it should do pure estimates. The > property then gets cached if it doesn't depend on assumptions, or if > it only depends on *prebreak-estimate* (in that case with two cached > value, prebreak and postbreak), but not if the callback uses > *prebreak-estimate-start* or *prebreak-estimate-end*. I'll have to > experiment with caching strategies, but this is the current idea. OK. I'm curious to see how that turns out. Does every call to get_property() will have to check the fluid as well to see if it should cache the computed value? How does the caching framework know if the computation depends on the assumption? -- Han-Wen Nienhuys - hanw...@gmail.com - http://www.xs4all.nl/~hanwen
Re: C++ question on wrapper API for setting Guile fluids
> Le 21/04/2022 11:05, David Kastrup a écrit : > Just for the record, your usage would not fit with the existing > lily/include/fluid.hh , The existing code in fluid.hh is concerned with retrieving fluids. I'm asking about setting them. Whether the new code can go in fluid.hh is a question, but it is new code. > and scm_c_with_fluid does not suffice? It would suffice, but it does not work with C++ lambdas, which makes it inconvenient.
Re: C++ question on wrapper API for setting Guile fluids
Jean Abou Samra writes: > Hi, > > It's me again ... > > I am working on code that pervasively utilizes Guile fluids. They should > be set in dynamic scopes. In C++, usage of the Guile API looks like this: > > scm_dynwind_begin (); > scm_dynwind_fluid (fluid, value); > ... > scm_dynwind_end (); Just for the record, your usage would not fit with the existing lily/include/fluid.hh , and scm_c_with_fluid does not suffice? -- David Kastrup
Re: C++ question on wrapper API for setting Guile fluids
Hi Luca, Thanks for your insights! Much appreciated. Le 21/04/2022 à 08:55, Luca Fascione a écrit : I'd think you can up this by one, and get a cleaner looking piece of code if you implement scm_dynwind_fluid() as a forwarded method on your context: { Dynwind_context dwc; // overloaded so you can call dwc(SCM_F_DYNWIND_REWINDABLE); dwc.fluid (fluid1, value1); dwc.fluid (fluid2, value2); dwc.unwind_handler(handler, data, flags); // overloaded for the SCM vs void* cases, dwc.rewind_handler(handler, data, flags); // overloaded for the SCM vs void* cases, // maybe it ought to check if the constructor was DYNWIND_REWINDABLE and complain // (only in debug builds?) if things are not set up right dwc.free(something); } 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. However in all this, I must say I don't understand this passage in manual: The context is ended either implicitly when a non-local exit happens, or explicitly with scm_dynwind_end. You must make sure that a dynwind context is indeed ended properly. If you fail to call scm_dynwind_end for each scm_dynwind_begin, the behavior is undefined. It seems to me the first phrase and the rest slightly contradict each other: as I hear it, the first phrase says "either the C side calls scm_dynwind_end(), OR a non-local exit happens", whereas the rest seems to be saying "the C side _shall_ call scm_dynwind_end". This bothers me, because in the second case our C++ is nice and lovely, but in the first meaning the destructor of dwc has to somehow figure out whether a non-local exit has happened, and avoid calling scm_dynwind_end(). And I don't think scm library can cope on its own, because these things look to me like they would nest, so making scm_dynwind_end() idempotent without some sort of explicit marker on the scope seems... hard. So yes, I'd think RAII is the idiomatic way to go, I would add the wrappers because they make the pattern cleaner, but do figure out what's up with this last question first, because it could bring it all crumbling down. Let's do a little test: diff --git a/lily/main.cc b/lily/main.cc index c98db72e8c..b8e928e29c 100644 --- a/lily/main.cc +++ b/lily/main.cc @@ -496,6 +496,21 @@ do_chroot_jail () } #endif +class Dynwind_context +{ +public: + Dynwind_context () + { + message ("starting dynwind context"); + scm_dynwind_begin (static_cast (0)); + } + ~Dynwind_context () + { + message ("ending dynwind context"); + scm_dynwind_end (); + } +}; + static void main_with_guile (void *, int, char **) /* @@ -505,6 +520,17 @@ main_with_guile (void *, int, char **) * to main_with_guile. */ { + message ("normal termination:"); + { + Dynwind_context dwc; + message ("before normal termination"); + } + message ("termination by exception:"); + { + Dynwind_context dwc; + message ("before termination by exception"); + scm_throw (ly_symbol2scm ("x"), SCM_EOL); + } /* Engravers use lily.scm contents, so we need to make Guile find it. Prepend onto GUILE %load-path. %load-path is the symbol Guile searches for .scm files Running this, I get: normal termination: starting dynwind context before normal termination ending dynwind context termination by exception: starting dynwind context before termination by exceptionBacktrace: In ice-9/boot-9.scm: 1752:10 1 (with-exception-handler _ _ #:unwind? _ # _) In unknown file: 0 (apply-smob/0 #) ERROR: In procedure apply-smob/0: Throw to key `x' with args `()'. As you can see, scm_dynwind_end () is not called on the non-local exit. There are actually two kinds of non-local exits that we are talking about here: the C++ ones, and the Guile ones. C++ does them via return, break, continue, C++ exceptions. Guile does them via Guile exceptions and continuations. When Guile captures a continuation, for example, it just copies the whole C(++) stack in an object, and reinstating the continuation simply copies the saved stack data back into the stack. See the end of https://www.gnu.org/software/guile/manual/html_node/Continuations.html Exceptions are kind of a special case of this (except that in Guile 2 and later it looks like they are actually implemented with delimited/composable continuations, aka prompts, rather than traditional continuations, but I haven't looked at that too closely). Thus, C++ RAII stuff ensures destructors get called upon C++ non-local exits, but not Guile ones. So the meaning of the docs here is that you must insert a call to
Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 10:38, Han-Wen Nienhuys a écrit : On Thu, Apr 21, 2022 at 12:04 AM Jean Abou Samra wrote: I am working on code that pervasively utilizes Guile fluids. They should be set in dynamic scopes. That sounds scary. Care to tell more? What is scary about it exactly? I am trying to reimplement purity in terms of fluids, so the set of parameters is not hardcoded to 'start, end' and all the code doesn't have to be littered with functions working both as pure and impure and forwarding start/end to the property callbacks they cause. Essentially, this should look like { Dynwind_context dwc; dwc->make_assumption (Lily::prebreak_estimate, SCM_BOOL_T); ... get_property (grob, "property") ... } or in Scheme: (under-assumptions ((*prebreak-estimate* #t)) ...) and by virtue of the dynamic context, the callback that computes the grob property understands that it should do pure estimates. The property then gets cached if it doesn't depend on assumptions, or if it only depends on *prebreak-estimate* (in that case with two cached value, prebreak and postbreak), but not if the callback uses *prebreak-estimate-start* or *prebreak-estimate-end*. I'll have to experiment with caching strategies, but this is the current idea. The advantage is that 95% of code that needs to interact with purity (via ly:make-unpure-pure-container, get_maybe_pure_property, etc.) no longer needs to do so. Purity becomes a very localized thing and no longer pervades the code base. It can also be worked on more easily; my work on https://gitlab.com/lilypond/lilypond/-/merge_requests/744 involves introducing pure widths, and I don't want to add maybe_pure_x_extent and change hundreds of callbacks so they do maybe_pure_x_extent instead of extent ( X_AXIS). There is the same need in order to properly implement functionality demonstrated in a recent -user thread https://lists.gnu.org/archive/html/lilypond-user/2022-04/msg00062.html where LyricText.X-offset needs a pure/unpure distinction in order to avoid after-line-breaking. Also, since whether callbacks access start and end is now known, pure properties that depend on whether the call is pure or not but not on start and end (namely the vast majority of them) can start getting cached. Right now, we use a trick to cache item pure heights, assuming that Y-extent/Y-offset does not depend on start/end for items (Item::pure_y_extent). This can then be done for spanners as well. I haven't gotten as far as a working proof of concept, but I expect a speedup. This is essentially a remix of an idea from David: https://lists.gnu.org/archive/html/lilypond-devel/2015-05/msg00397.html Jean
Re: C++ question on wrapper API for setting Guile fluids
On Thu, Apr 21, 2022 at 12:04 AM Jean Abou Samra wrote: > I am working on code that pervasively utilizes Guile fluids. They should > be set in dynamic scopes. That sounds scary. Care to tell more? -- Han-Wen Nienhuys - hanw...@gmail.com - http://www.xs4all.nl/~hanwen
Re: Missing dependencies in doc build after addition of PDF syntax highlighting?
On Thu, 2022-04-21 at 09:13 +0200, Jean Abou Samra wrote: > Le 21/04/2022 à 08:31, Jonas Hahnfeld a écrit : > > On Tue, 2022-04-19 at 20:13 +0200, Jean Abou Samra wrote: > > > Hi, > > > > > > This used to work for me in order to build just one document, as > > > opposed to building the full documentation: > > > > > > make -j9 CPU_COUNT=9 -C Documentation out=www out-www/en/internals.pdf > > > > > > This is also recommended in the CG. > > Where? I couldn't find it. > > > Here: > > https://lilypond.org/doc/v2.23/Documentation/contributor/generating-documentation#documentation-editor_0027s-edit_002fcompile-cycle > > The third section on that page, "Building a single document", also uses > 'make out=www out-www/en/contributor.pdf' after 'cd Documentation/'. This says "to rebuild only 'contributor.pdf'", which should still work fine in an incremental build, no? Jonas signature.asc Description: This is a digitally signed message part
Re: Missing dependencies in doc build after addition of PDF syntax highlighting?
Le 21/04/2022 à 08:31, Jonas Hahnfeld a écrit : On Tue, 2022-04-19 at 20:13 +0200, Jean Abou Samra wrote: Hi, This used to work for me in order to build just one document, as opposed to building the full documentation: make -j9 CPU_COUNT=9 -C Documentation out=www out-www/en/internals.pdf This is also recommended in the CG. Where? I couldn't find it. Here: https://lilypond.org/doc/v2.23/Documentation/contributor/generating-documentation#documentation-editor_0027s-edit_002fcompile-cycle The third section on that page, "Building a single document", also uses 'make out=www out-www/en/contributor.pdf' after 'cd Documentation/'. [...] If I do 'make -j9 CPU_COUNT=9 doc' instead, the start of the build shows the generation of the missing files: Making .pl files for lm fonts < afm Making tex/out-www/lmttb.tfm < pl Making tex/out-www/lmttbo.tfm < pl Making tex/out-www/lmttr.tfm < pl Making tex/out-www/lmttro.tfm < pl Making .map and .enc files for lm fonts (tex) Am I doing something wrong (in which case the CG needs updating) or is the doc build missing some dependencies? This is totally expected to me, 'make doc' first needs to generate the fonts, which is done in tex/. Directly descending into a directory can only work for incremental builds. The specific way to build a single document doesn't matter all that much to me. I would just like there to be a way. Thanks, Jean
Re: C++ question on wrapper API for setting Guile fluids
On Thu, Apr 21, 2022 at 8:12 AM Jean Abou Samra wrote: > Le 21/04/2022 à 04:57, Dan Eble a écrit : > > { > >// dwc constructor calls scm_dynwind_begin () > >Dynwind_context dwc; > >scm_dynwind_fluid (fluid1, value1); > >scm_dynwind_fluid (fluid2, value2); > >. . . > >// dwc destructor calls scm_dynwind_end () > > } > > > > Why not. There is likely just one caller that will need to introduce > several > fluids at once, but it is probably clearer this way. > I'd think you can up this by one, and get a cleaner looking piece of code if you implement scm_dynwind_fluid() as a forwarded method on your context: { Dynwind_context dwc; // overloaded so you can call dwc(SCM_F_DYNWIND_REWINDABLE); dwc.fluid (fluid1, value1); dwc.fluid (fluid2, value2); dwc.unwind_handler(handler, data, flags); // overloaded for the SCM vs void* cases, dwc.rewind_handler(handler, data, flags); // overloaded for the SCM vs void* cases, // maybe it ought to check if the constructor was DYNWIND_REWINDABLE and complain // (only in debug builds?) if things are not set up right dwc.free(something); } However in all this, I must say I don't understand this passage in manual: The context is ended either implicitly when a non-local exit happens, or explicitly with scm_dynwind_end. You must make sure that a dynwind context is indeed ended properly. If you fail to call scm_dynwind_end for each scm_dynwind_begin, the behavior is undefined. It seems to me the first phrase and the rest slightly contradict each other: as I hear it, the first phrase says "either the C side calls scm_dynwind_end(), OR a non-local exit happens", whereas the rest seems to be saying "the C side _shall_ call scm_dynwind_end". This bothers me, because in the second case our C++ is nice and lovely, but in the first meaning the destructor of dwc has to somehow figure out whether a non-local exit has happened, and avoid calling scm_dynwind_end(). And I don't think scm library can cope on its own, because these things look to me like they would nest, so making scm_dynwind_end() idempotent without some sort of explicit marker on the scope seems... hard. So yes, I'd think RAII is the idiomatic way to go, I would add the wrappers because they make the pattern cleaner, but do figure out what's up with this last question first, because it could bring it all crumbling down. HTH Luca
Re: Missing dependencies in doc build after addition of PDF syntax highlighting?
On Tue, 2022-04-19 at 20:13 +0200, Jean Abou Samra wrote: > Hi, > > This used to work for me in order to build just one document, as > opposed to building the full documentation: > > make -j9 CPU_COUNT=9 -C Documentation out=www out-www/en/internals.pdf > > This is also recommended in the CG. Where? I couldn't find it. > [...] > If I do 'make -j9 CPU_COUNT=9 doc' instead, the start of > the build shows the generation of the missing files: > > Making .pl files for lm fonts < afm > Making tex/out-www/lmttb.tfm < pl > Making tex/out-www/lmttbo.tfm < pl > Making tex/out-www/lmttr.tfm < pl > Making tex/out-www/lmttro.tfm < pl > Making .map and .enc files for lm fonts (tex) > > > Am I doing something wrong (in which case the CG needs updating) or > is the doc build missing some dependencies? This is totally expected to me, 'make doc' first needs to generate the fonts, which is done in tex/. Directly descending into a directory can only work for incremental builds. Jonas signature.asc Description: This is a digitally signed message part
Re: C++ question on wrapper API for setting Guile fluids
Le 21/04/2022 à 04:57, Dan Eble a écrit : On Apr 20, 2022, at 18:04, Jean Abou Samra wrote: Calls to scm_dynwind_begin () and scm_dynwind_end () must be paired correctly. Obviously, if '...' contains statements causing non-local control flow like return, break, continue, and such, it is easy to miss a scm_dynwind_end (). I read that you can avoid that using RAII: Yes. { // Constructor does scm_dynwind_begin () and scm_dynwind_fluid () Fluid_setter setter (fluid, value); Might you want to call scm_dynwind_fluid () more than once? How about this? { // dwc constructor calls scm_dynwind_begin () Dynwind_context dwc; scm_dynwind_fluid (fluid1, value1); scm_dynwind_fluid (fluid2, value2); . . . // dwc destructor calls scm_dynwind_end () } Why not. There is likely just one caller that will need to introduce several fluids at once, but it is probably clearer this way. What disturbs me slightly with this approach is the variable 'setter', which will never be used, but must nevertheless be defined in order for the object not to be thrown away as temporary. If I understand you, turning the main effect (scm_dynwind_begin) into a side effect of the constructor bothers you. It wouldn't bother me as long as the class had a good name. I can think of two alternatives, but they have their own problems. Does that sound about right? Would this be considered an idiomatic approach? Yes. Thanks! Jean