guile-devel
[Top][All Lists]
Advanced

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

Re: Syntax checks


From: Lynn Winebarger
Subject: Re: Syntax checks
Date: Thu, 9 May 2002 00:59:32 -0500

On Tuesday 07 May 2002 14:24, Marius Vollmer wrote:
> Lynn Winebarger <address@hidden> writes:
> > [...] How will generics interact with the module system? How will
> > classes interact with nested modules?  I'll try to write some
> > (currently non-interpretable) code to illustrate what I'm thinking
> > about and how it should evaluate.
> 
> My current stance on this is that generics and classes should not be
> treated specially by the module system.  Just like functions, generics
> and classes are nameless objects that just happen to be accessible via
> some name (or more than one, or none).  Thus, modules should only be
> there to manage the name-space, not to create new (merged) generics, etc.

     I've had some trouble coming up with interesting examples.  My problem
is I want to make modules that encapsulate the fields of the object
and then import the fields in methods, but the syntax makes this difficult, 
and so does the MOP.  Of course, it's easy to encapsulate the class and 
be picky about what accessors and methods get exported. 
Essentially, in my view, objects and modules are both lexical environments,
but modules are (generally at least) unique whereas lots of objects might 
provide the same environment (in terms of the variables they close over).
     I'm not sure what you mean by merged generics.  Does GOOPS manage
its own namespace (in terms of finding generics and parent classes) or
do classes and generics really get encapsulated in modules (now and
in principle)?

> >      It's interesting because the old code continues to refer to the
> > variable binding and yet you can't create a new reference to that
> > location.  This seems to be the logical result of requiring the
> > ability to specify syntax in non-operator positions
> > ("identifier-syntax").  My thinking is that while they're logically
> > separate environments, they should should be implemented in one
> > table, where each entry has 2 possible entries (one for syntax and
> > one for variable).
> 
> Yes, indeed.  Guile is somewhat confused about this right now: it does
> symbol -> variable -> macro instead of symbol -> macro.
> 
       I have been looking at the code to see if I can fix it.  There appears
to be some issues with the implementation of fluids that could be fixed
at the same time, though.  See below (I've re-ordered some pieces).

> Not much, I'd say.  The main thing I took away from signatures is that
> they are compile-time constructs, not run-time constructs.  (If I
> understood them right.)  That is, what binding comes from what module
> is fixed at compile time, not at load time.  Knowing at compile time
> which module to look in for a given symbol is important for macros,
> and also for doing important optimizations (such as inlining of
> fixnum-+, say).
> 
> > This touches on something I've noticed while browsing - why are
> > there so many smobs in the core interpreter?  Is it because you
> > can't export macros to C automatically, or is there a deeper reason?
> 
> I don't understand.  How would macros reduce the need for smobs?
> 
      I was specifically thinking of fluids.  Disregard threads for a moment.
It appears (and I emphasize appears as I am not completely sure) that
the fluids in guile are only work for global definitions.  If so it's incorrect.
Any variable, global or lexical should be fluid-settable (so to speak).  Take
Dybvig's macro definition:
(define-syntax fluid-let
    (syntax-rules ()
        (_ ((x v)) e1 e2 ...)
            (let ((y v))
               (let ((swap (lambda ()
                                    (let ((t x))
                                       (set! x y)
                                       (set! y t)))))
                  (dynamic-wind
                        swap
                         (lambda ()  e1 e2 ...)
                         swap))))))

Hence
(define x 7)
(define foo (lambda () x))
(let ((x 5))
    (letrec ((bar (lambda () x))))
         (fluid-let ((x 0))
               (list (foo) (bar)))))
=> (7 0)

whereas in the current scheme (I think) you'd get (0 5).  It took me
a while to understand this approach (hygenic macros make "y" just
some generated symbol - new storage - to hide the "real" value
of the variable (lexical or global) until the expressions are done, and
the dynamic wind ensures that it's seen by any invocation of a continuation
captured inside e1 e2 ... .)

     However, there is a problem when you add threads (cooperative or
interruptable) that the fluid binding should only apply to the "dynamic
extent" in a single thread (which is what dynamic-root is/was for I believe?),
which makes a macro definition more difficult.
     I think the way to attack this is to make each lexical-environment have
a variable-per-thread, and an underlying variable, and each variable lookup
check the per-thread location first which might just contain the reference
to the underlying variable, or a thread-local fluid binding.  Macros probably
have to be treated the same way to get fluid-let-syntax to work right.
       By the by, I think this touches on issues in the comments preceding
lookupcar.  If I read it right, the main issue arises when the expansion stage
doesn't properly precede the interpretation stage and two different threads
might try to do a combined expand/execute on the same s-expression.  It
seems to me it would be solved by the proper separation - that is, threads
should only be "sharing s-expressions" through closures stored in common
variables.  One thread should be do the reading and expanding before any
storage of the resulting object happens.   The only problem would be if you
purposefully did an eval! operation on a quoted sexpression in two different
threads, in which case you sort of deserve what you get.  I think that applies
to either the coop threads or interruptable threads (I know guile doesn't
work with them now, but if it did it wouldn't make a difference).

> >       Another issue - how would you direct the compiler to export C
> > "bindings" (e.g. a trampoline shared library and header file).
> 
> What do you mean?  How to export bindings from a module defined in C?
> 
   No, I meant if we had a guile compiler, how would we direct it to export
bindings (i.e. header files) and a C API compliant shared library that 
trampolined
into the real code.  And when I say export, I mean where the C caller wouldn't
use SCM values, but the exporter would generate translations as part of the
trampoline.  Although this is kind of specious issue at the moment.  It's just 
what
I was thinking about in terms of compiled modules (generally) corresponding to 
shared libraries, and how guile definitions could be made "first class" wrt C
functions.
    Just to express my opinion, scheme compilers should be written in scheme.  
It's
a moral imperative.  Leave the interpreter in C and lift the common data into
a schemey format, autogenerating the C definitions.  That'd be my approach.

Lynn



reply via email to

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