This is the mail archive of the guile@cygnus.com mailing list for the guile project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: "Current" solution for generalized set!


Chris.Bitmead@misys.com.au writes:

> dispatch_table[scm->type]->display(scm);
> 
> I can't see that it could be inlined beyond this because we don't know the
> run-time type.

Let's say that we're compiling module B which imports bindings
read-only from module A, among them the variable x.

In our program we have the expression

  (display x)

Let's now assume that x is a free variable, i.e., it is not shadowed
by any local binding, but refers to the imported, read-only, x.

Then we can trust x always to be of type T, so that we can compile

  (display x)

to

  display_T (x);

If x is the string "Hello World!\n", we can go further:

  printf ("Hello World\n");

Note how this depends on the compiler's ability to determine a
constant bond between x and "Hello World\n".  If this binding was
dynamic, we couldn't compile it to the last statement above.

> Similarly, I would have thought a set! could be inlined as
> dispatch_table[scm->type]->set(scm, value);

I don't understand how the above expression relates to the current
discussion.  What is `scm'?  Note that what set! needs to do is to
find the setter which is associated with the getter being used in the
expression.  It is not a question of type dispatch.

> It's not obvious to me how the idea of instead changing the procedure
> object is "more local". A "plain dynamic dispatch set!" would be re-using
> an idea already in the language.

I have not talked about "changing" the procedure.  The proposal means
making a new procedure from the getter and the setter.

With "plain dynamic dispatch set!" I thought you were referring to the
old proposal which meant associating the getter with setter by use of
a procedure property (which, BTW, is not a standard Scheme feature).

Did you refer to something else?

The new proposal is more local because instead of relying on a
mechanism which can associate setters to *any* procedure, we restrict
this bond to procedures constructed with make-procedure-with-setter.

> But what I don't get is why we want to map procedures to setters at
> all.  Surely what we want to do is map types to setters. After all
> it is going to be the type of the object we are trying to set a
> member of which determines which setter to use.
> 
> I must be missing something big here.

Yes, this is probably the main cause of the confusion.

The "generalized" set! idea is exactly about mapping getters to a
setters.  Here are two examples of how set! expressions are
transformed:

  (set! (car x) y) --> ((setter car) x y)
  (set! (cdr x) y) --> ((setter cdr) x y)

Obviously, we want (setter cxr) to return set-cxr!.

Note that both setters work on the same type: a pair.
What determines which setter to use is the *getter* we're using.

> > We also avoid associating a setter slot with each procedure.
> 
> But who really wants to associate setter slots with procedures?

The old proposal did this (using set-procedure-property!).

> >It's a bit sad that I'm the only one that previously tried to protect
> >the simplicity of the language.
> 
> I think it's more a case of everyone having a different idea of what
> protecting the simplicity of the language actually means.

In my case it meant advocating for not extending the set! form, but
require that the first argument is a variable name.

But now I've changed opinion: The new solution doesn't do anything
strange.  It basically adds a constructor (an ordinary procedure)
which takes standard Scheme types (procedures) and return a standard
Scheme type (procedure).  There's no need of a table, and the
extended set! form can be compiled to efficient code.

> My concern is not that your idea is or isn't efficient. It is that
> the whole design seems to rely on being able to modify the guts of
> the system in order to be able to implement efficiently.  If I were
> to take some arbitrary R5RS Scheme, and without modifying it try to
> implement this scheme, I would need some ugly form of table lookup
> or something (I think).

Here's a plain (untested) R5RS implementation:

(define make-procedure-with-setter #f)
(define getter #f)
(define setter #f)

(let ((getter-cookie '(cookie))
      (setter-cookie '(cookie)))
  (set! make-procedure-with-setter
        (lambda (getter setter)
          (lambda args
            (cond ((eq? (car args) getter-cookie) getter)
                  ((eq? (car args) setter-cookie) setter)
                  (else (apply getter args))))))
  (set! getter
        (lambda (proc)
          (proc getter-cookie)))
  (set! setter
        (lambda (proc)
          (proc setter-cookie))))

The set! form in the prototype implementation is already R5RS (except
for the way to write macros).

If anyone can find a better design, which still can be compiled to
efficient code, I'd be very happy to see it.

/mdj