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] |
I think I understand now. Thanks for being patient with me. Your prime goal was to associate a getter function with a setter function. My ideas were about making sure that different classes of object could have setters with the same name. So I was concerned about dispatching over the class of object. Whereas your solution is about dispatching according to an actual instance of a procedure. I guess they are complementary concepts. It does suggest to me a more general mechanism for what you want to do though. What you want is to use the one function name, like "car" as the name of a getter and setter, depending on the usage. It suggests to me that you actually want to dispatch similar to CLOS except not on type, but on identity. Wouldn't it be cool if the CLOS system were expanded to encompass this idea? Generic functions are normally declared (define-generic name ((arg1 <arg1type>) ...)) What if instead of a type you could have a symbol? Like this.. (define-generic setter ((proc 'car)) set-car! ) Then when you call (setter car) it would call the above generic function returning set-car!. Thus (set! (car foo) v) becomes.. ((setter 'car ) v foo) becomes.. (set-car! v foo) Just looking for a way to make a specific solution more general... Depending on how CLOS is implemented, I can imagine this might "just work" if CLOS doesn't insist that the thing dispatched on is a class. Then you could also have a generic initializer... (define-generic initializer ((proc 'cdr)) (lambda (obj) (set-cdr! obj '()))) and perhaps (init! (cdr foo)) becomes.. ((initializer 'cdr) foo) becomes.. ((lambda (obj) (set-cdr! obj '())) foo) becomes.. (set-cdr! foo '()) 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