guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: scm_* API extension? [was] scm_* API question


From: Rob Browning
Subject: Re: scm_* API extension? [was] scm_* API question
Date: Mon, 05 Aug 2002 13:45:53 -0500
User-agent: Gnus/5.090006 (Oort Gnus v0.06) Emacs/21.2 (i386-pc-linux-gnu)

Han-Wen Nienhuys <address@hidden> writes:

> f1.ly
>
>        #(set! global-foo-option #t) ;; default  = #f
>        \score  {\notes { .. } }
>
> f2.ly
>
>       \score { \notes { ..other notes.. } }
>
> What really happens during execution depends on the order of
> execution: if you do
>
>       lilypond f1 f2
>
> then f2 is processed with global-foo-option set to #t. If you change
> the order, then f2 is processed with global-foo-option set to #f.
>
> It would be nice if we could have some kind of copy-on-write system
> for variables, so that I can reset the state of the variables before
> processing each new file.
>
> [disclaimer, I know nothing of advanced Scheme techniques, I might be
> missing some basic idiom here completely.]

I'm not familiar with what lilypond is doing, but can you do one of:

  * create a new "anonymous module" (as I described in an answer to
    the mod_guile thread) for each file/"session" you're going to
    load, initialize the module by calling

      (eval '(ly-initialize-sandbox) *current-user-module*)
 
    then execute the user's code in there with another appropriate
    eval.

  * Don't use globals.  Hide all the lilypond specific state inside
    a relevant per-load-file data structure that's either newly
    created or reinitialized with each file load.

  * Have a suitable initialization function that resets the state of
    the global envt appropriately and call that between .ly files
    loads.  In general, this is easier if you don't make changing
    global variables part of the public API -- i.e. *everything*
    should be a function like (ly-set-global-foo-option! value).  This
    way you have a lot more control over what's going on and it's a
    lot easier to keep track or clean up after user changes.

    For (simplistic) example, if you write an editor and don't make
    raw set!'s part of the public API, then you can more easily
    implement undo:

      (define (sillyedit-change-margin-width! width)
        (push-undo!
          (let ((old-width (silly-edit-get-margin-width)))
            (lambda ()
              (se-lowlevel-set-margin-width! old-width))))
        (se-lowlevel-set-margin-width width))

    With this approach, multiple levels of undo just involve replaying
    the undo list (of course *really* getting undo/redo right is
    *much* harder).

    Anyway, IMO it's often better not to expose variables -- use
    functions for everyhing so you'll be able to rearrange your
    internal semantics later if you want/need to.  It's also easier
    if/when you ever want to migrate to a threaded environment.

  * create your own recursive descent mini-parser for the language in
    question (if it's sufficiently different from plain scheme, or if
    you need super-anal security or error checking), and just load and
    "evaluate" the .ly files with that parser.  You can reinitialize
    it between runs.

Hope this helps.

-- 
Rob Browning
rlb @defaultvalue.org, @linuxdevel.com, and @debian.org
Previously @cs.utexas.edu
GPG=1C58 8B2C FB5E 3F64 EA5C  64AE 78FE E5FE F0CB A0AD



reply via email to

[Prev in Thread] Current Thread [Next in Thread]