[Top][All Lists]
[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