guile-devel
[Top][All Lists]
Advanced

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

Re: Bug in eval-string?


From: Matthias Koeppe
Subject: Re: Bug in eval-string?
Date: Tue, 20 Aug 2002 13:39:50 +0200
User-agent: Gnus/5.090004 (Oort Gnus v0.04) Emacs/21.1.80 (sparc-sun-solaris2.7)

Marius Vollmer <address@hidden> writes:

> Matthias Koeppe <address@hidden> writes:
>
>> I would like to refer you to the discussion archive of SRFI-15.
>
> Ahh, thanks.  I quickly skimmed the discussion and I think I have a
> slightly different view of fluid-let re concurrent execution.
>
> I doesn't really make sense to me to say that fluid-let works/works
> not with concurrent execution.  It is global lexical variables that
> don't work with threads, and they don't work with threads regardless
> of whether they are set by fluid-let or by some other construct.
>
> If using global variables is wrong, then using them together with
> fluid-let can't make them right.  If all fluid-let can affect is
> lexical variables, then it is not very useful in a threaded system.
> You could use it to set global variables that should not be
> thread-local, or non-global lexical variables that are per-se
> thread-local.  These are rather untypical things, I agree, and we
> should not lure people into doing them only because they are more
> convenient than the correct thing.
>
> But our fluid-let would be able to affect more than just variables.
> The extended (set! (accessor ...) ...) syntax can also used with
> fluid-let and with it, you can affect abstract storage locations.
> When you use storage locations that are themselves thread-local, then
> fluid-let will also work in a threaded environment.

> The decision that must be taken correctly is how to implement your
> global state, not whether to use fluid-let to twiddle it.
>
> For us, the correct way to store thread-local data is with a fluid.
> Thus, you might reason that one would use fluid-let mostly with
> fluids, but we already have a device for them, which is with-fluids.
> So fluid-let would be superfluous again.
>
> But fluids are by far not the only thread-local things that one might
> want to bind dynamically.  You could also have some data structure
> that is pointed to by some thread-local global variable and you might
> want to dynamically bind a slot of this structure.  Or this structure
> might be shared by a group of cooperating threads and setting a field
> in it would thus affect all of them.

I think it is already a very bad idea to think about temporarily
mutating slots of data structures as "binding".  See also below.

The good thing about fluids is that they are regular Scheme values.
This means that we can put them not only in global variables but also
in lexical variables and other data structures.  The WITH-FLUIDS
syntax also deals with those fluids, not only with fluids stored in
global variables.

> Also, fluids are the basis for thread-local storage, but they might
> not be enough.  You might want to layer some notification protocol on
> top of them.  Say the GUI thread should be signalled when you set a
> 'busy' flag.  You could have a 'settable funtion' "busy" that knows
> where the GUI thread is and (set! (busy) #t) would signal it so that
> it can change the display.  Being able to say
>
>     (fluid-let (((busy) #t))
>       ...)
>
> looks very attractive to me (and is entirely correct because "busy" is
> correct, not because fluid-let is somehow thread-safe).

It doesn't look attractive to me.  I am afraid people will simulate
control structures via getters and setters.  BUSY is the first step
into this direction.  This will lead to a C++-ish overloading mess,
where you never know what an operation will do unless you know exactly
the type of the objects involved.

The Scheme way would be to make a new control procedure

    (with-being-busy THUNK)

or/and a macro.  This is much cleaner, and much more expressive than
"dynamically binding" a generalized location that executes arbitrary
code when you get or set its value.

>> 1.  If you provide an overly convenient construct named "WITH", people
>>     will write code (and libraries) using it for dynamic scoping,
>>     rather than using fluid variables with the right dynamic-scoping
>>     construct, WITH-FLUIDS.
>
> I have more faith, it seems.  I do think that they will see the light,
> given proper documentation.
>
>> 2.  As a side note, let us see how FLUID-LET looks if you want to
>>     use it with real fluids:
>> 
>>         (fluid-let (((fluid-ref my-fluid) value))
>>            ...code...)
>> 
>>     Using WITH-FLUIDS would certainly be prettier here:
>> 
>>         (with-fluids ((my-fluid value))
>>            ...code...)
>
> We can improve the former to
>
>         (fluid-let (((my-fluid) value))
>           ...code...)
>
> when fluids are settable directly.

I strongly oppose the idea of making fluids "settable directly".  I
assume this would mean to make them "gettable directly" as well via
procedure-call syntax.  This is simply over-concise.  We would lose
expressivity of code using fluids, as only a pair of parens would
distinguish it from regular variable use.

>> I don't think it is a good idea to introduce core syntax for a
>> dynamic-scoping hack for general "settable things".  
>> 
>> I certainly don't want to see code like this:
>> 
>>      (fluid-let (((caddr l) (...))
>>                  ((list-ref l 17) (...)))
>>         ...)
>
> But when that is what it takes?  I would be ware of code like that
> myself, but do you think that people will start writing things like
> that just because they suddenly have fluid-let?  Wouldn't they rather
> use eval anyway? ;)
>
>> What "general settable things" did you have in mind?
>
> Structure slots, for example.  See above.

I was afraid you would say that.  I think it is very bad style to make
temporary mutations on data structures.  It's not getting better if
you mutate named slots rather than mutating the CADDR as in the
example code I gave above. 

If one really has to make temporary mutations, then the dynamic-wind
mess makes one think about it.  Again the generalized FLUID-LET
construct is simply too convenient.

> [...]

Marius, I have also followed the discussion on emacs-devel, which
seems to be the motivation for the discussion here on guile-devel.  I
think that we should not get carried away by the low-level
functionality (and the performance hacks) of Emacs variables, with the
"swapping in-and-out" of values, and of buffer-local and frame-local
variables.

The only reason why I would be interested in a Guile-based
implementation of Emacs is the hope for a clean, thread-safe Lisp
engine, which would allow for a multi-threaded Emacs.  We can't reach
this goal if we copy all the inherently single-threaded stuff
(swapping in and out values, as with FLUID-LET) from the Emacs Lisp
engine into Guile.

We should first find the right data model for Emacs "variables".  Only
as a second step, we should think about convenient syntax to access
the variables from Scheme code (and how to translate Emacs Lisp code
into Scheme code).

Emacs "variables" simply aren't variables.  They are functions
(procedures-with-setters) depending on the "current" buffer and frame
and on the "dynamic environment".  Here is a possible prototype
implementation.

  ;; pseudo-code

  (define-structure <emacs-variable>
    global-value   
    dynamic-value-fluid   ; a fluid
    buffer-local-values   ; alist or hash table mapping buffers to values
    frame-local-values    ; likewise
  )

  (define* (get-emacs-variable-value emacs-variable 
               #:optional (buffer (fluid-ref *current-buffer*))
                          (frame (fluid-ref *current-frame*)))
     (cond
      ((assq buffer (buffer-local-values emacs-variable))
       => cdr)
      ((assq frame (frame-local-values emacs-variable))
       => cdr)
      ((not (eq? (fluid-ref (dynamic-value-fluid emacs-variable))) *undefined*)
       (fluid-ref (dynamic-value-fluid emacs-variable)))
      (else
       (global-value emacs-variable))))
       
  ;; setter likewise
      
The Emacs Lisp LET syntax would translate to a WITH-FLUIDS on the
dynamic-value-fluid of the Emacs variable.

Regards,

-- 
Matthias Köppe -- http://www.math.uni-magdeburg.de/~mkoeppe




reply via email to

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