From pc at p-cos.net Fri Sep 5 13:14:31 2008 From: pc at p-cos.net (Pascal Costanza) Date: Fri, 5 Sep 2008 15:14:31 +0200 Subject: [closer-devel] slots on layers In-Reply-To: References: <6777FEE5-5846-4B94-9772-9865F03F21BF@p-cos.net> Message-ID: <45F07A27-8392-4DD8-9689-A5A6FD21E3B4@p-cos.net> Hi again, This is a useful discussion, because it's about something that I wanted to integrate into ContextL for some item anyway, and we can now make some "right" decisions here. On 31 Aug 2008, at 00:44, Attila Lendvai wrote: >> What you describe seems to be a classic scenario for using first- >> class >> continuations. What I already have on my todo list for ContextL is >> support > > to be more precise what we need is only one-shot continuations, which > can simply be done with a lambda plus some macrology without much > overhead. OK, that sounds good. (Although I would like to make it work with more full-fledged continuations as well.) >> for first-class dynamic closures. The idea would be that you can say >> something like (capture-dynamic-bindings), which gives you a first- >> class >> representation of all special variables, which you can later >> reinstate by >> something like (with-reinstated-dynamic-bindings ...). Such a dynamic >> closure facility would capture the current representation of active >> layers >> (because that's in a special variable), as well as, for example, >> special >> slots both in the layers and in other objects. >> >> (It won't be as general as that, I will have to require registering >> the >> special variables that you want to see captured, but I think I can >> make this >> relatively non-intrusive.) >> >> Would that solve your problem? > > i think it would, but i still don't see why it is worth it. what you > describe seems to be a lot more complex than if we cloned a new > instance at each change to the layer context. AFAICS, from the user's > POV the two solutions would be equivalent (except the different > performance characteristics), but the implementation of the > make-instance/copy-slots seems much more simple with potentially less > surprises. True, that implementation seems more simple (although I think my suggestion is not that complicated either, but I'm probably not communicating it well enough at the moment). I tend towards the first-class dynamic environments because it sounds to me to be the "right" solution, whereas what you suggest seems very specific to some (important) detail ContextL. My hope is that the dynamic environments could be generalized in such a way that they become useful outside of ContextL as well. They will probably be part of the ContextL library, but it should be possible to use them without using any of ContextL's other features. (It is my strong belief that language constructs should be as independent of each other as possible.) > as of the performance, these layer prototype instances would have > standard slots that are much faster to access, while layer activation > would be slower, but that's rare (at least in our use-cases). in fact > the entire contextl related performance impact on our application is > probably negligible, and probably most of it comes from the extra > dispatch parameter. I'm actually not so worried about performance either, it's just a nice side effect if you can get good performance, but it's not on the top of my priority list. > i don't want to say that first class dynamic closures are not useful > in general, but in this situation it feels like too much machinery. I think I can make it work in such a way that it will feel very seamless. My idea is that the current context parameter and any special slots defined in layered and special classes will be automatically captured by default, without you having to worry about anything. I'm very certain that this should work (as always, it could have nasty corner cases that I don't know about yet, of course). > we already have a more fine-grained protocol to restore the dynamic > environment when for example a partial ajax rendering happens > somewhere inside the component hierarchy (components can specialize > the call-in-component-environment method, which is called on the > parent path of the component, one by one). most, but not all of its > usage is restoring dynamic variable bindings that could be covered by > capture-dynamic-bindings, but the protocol is more flexible than that. > it costs us a dozen of extra method calls, but our main priority is > code maintainability/flexibility/reuse, not speed. I am very interested to hear more about this, because this seems to be a part where I can double check whether "my" dynamic environments are general enough to support such things: + To what extent is your machinery more fine-grained? Can you select which special variables are captured and which aren't? Or do you mean something else here? + Do you have some source code publicly available where this is provided and used? I would like to take a look at it, if you are fine with that. > i'm sorry if i sounded negative, but i don't have a fine enough > english for this. and i'm just a user anyway, so take it all with a > piece of salt... :) i may even not see the whole picture or an > important detail. Don't worry, I also don't have a complete view of the whole picture, that's why it's good to have this discussion. Best, Pascal -- Pascal Costanza, mailto:pc at p-cos.net, http://p-cos.net Vrije Universiteit Brussel, Programming Technology Lab Pleinlaan 2, B-1050 Brussel, Belgium From drewc at tech.coop Fri Sep 5 21:27:16 2008 From: drewc at tech.coop (Drew Crampsie) Date: Fri, 5 Sep 2008 14:27:16 -0700 Subject: [closer-devel] slots on layers In-Reply-To: <45F07A27-8392-4DD8-9689-A5A6FD21E3B4@p-cos.net> References: <6777FEE5-5846-4B94-9772-9865F03F21BF@p-cos.net> <45F07A27-8392-4DD8-9689-A5A6FD21E3B4@p-cos.net> Message-ID: Hey All, I have a need for a mechanism similar to the one being described. I use ContextL with continuations, and i already use something similar to what Attila was describing. First some example code, with comments. In LoL we use objects called "descriptions" to control how an object is displayed. These are essentially layers with per-layer-slot-value semantics implemented using anonymous layered generic functions. (define-description bar ()) (define-description foo () ((attribute-with-value :label "A value:" :value 'foo-value)) (define-description foo () ((attribute-with-value :label "A different value:" :value 'foo-in-bar-value)) (:in-description bar)) (defun display-an (a) (format t "~A ~A%" (attribute-label a) (attribute-value)) (let* ((description (find-description 'foo)) (attribute (find-attribute description attribute-with-value)) ;; set up the environment to describe the object NIL using our description (with-described-object (nil description) ;; So, executing : (display-an attribute) ;; will print "A value: FOO-VALUE" ;; then if you do (with-active-descriptions (bar) (display-an attribute) ) ;; you'll get "A different value: FOO-IN-BAR-VALUE" ;; this is implemented via a more general mechanism such that: (with-active-descriptions (bar) (setf (slot-value attribute 'label) "A New Label")) ;; will set it permenantly in the bar description (layer) ) (with-active-descriptions (bar) (attribute-label attribute)) ;; => "A New Label" This works well for the most part, but the inability to capture the dynamic environment has lately become a problem. i've been able to hack it up via manually capturing and re-instating the bindings i need, but it's a hack and i'm sure there's a better way. Somethimg like : In ls2008/9/5 Pascal Costanza : >>> for first-class dynamic closures. The idea would be that you can say >>> something like (capture-dynamic-bindings), which gives you a first-class >>> representation of all special variables, which you can later reinstate by >>> something like (with-reinstated-dynamic-bindings ...). Such a dynamic >>> closure facility would capture the current representation of active >>> layers >>> (because that's in a special variable), as well as, for example, special >>> slots both in the layers and in other objects. >>> >>> (It won't be as general as that, I will have to require registering the >>> special variables that you want to see captured, but I think I can make >>> this >>> relatively non-intrusive This is exactly what i need. I had a few ideas on how to implement it, but it's not on my plate right now. I'd really like to see something like this are part of contextL, as i'm sure it would be much more thought-out than my implementation :). > > I think I can make it work in such a way that it will feel very seamless. My > idea is that the current context parameter and any special slots defined in > layered and special classes will be automatically captured by default, > without you having to worry about anything. I'm very certain that this > should work (as always, it could have nasty corner cases that I don't know > about yet, of course). I'de like to put my vote in for this solution, as it's very much in line with how i use contextl. It would enable me to greatly simplify my implementation in a lot of ways. I'd be more than happy to get into greater detail, i'm very glad we're having this discussion! :) Cheers, drewc From attila.lendvai at gmail.com Mon Sep 15 20:35:44 2008 From: attila.lendvai at gmail.com (Attila Lendvai) Date: Mon, 15 Sep 2008 22:35:44 +0200 Subject: [closer-devel] slots on layers In-Reply-To: <45F07A27-8392-4DD8-9689-A5A6FD21E3B4@p-cos.net> References: <6777FEE5-5846-4B94-9772-9865F03F21BF@p-cos.net> <45F07A27-8392-4DD8-9689-A5A6FD21E3B4@p-cos.net> Message-ID: > True, that implementation seems more simple (although I think my suggestion > is not that complicated either, but I'm probably not communicating it well > enough at the moment). my concerns are mostly related to debugging a random problem with this machinery operating in the background. also i think that it's a middle ground solution that on one hand has lost its simplicity and on the other hand doesn't give a generic solution, either (see below)... > I am very interested to hear more about this, because this seems to be a > part where I can double check whether "my" dynamic environments are general > enough to support such things: it's available at: http://common-lisp.net/cgi-bin/darcsweb/darcsweb.cgi?r=cl-dwim-wui;a=summary search for call-in-component-environment and with-restored-component-environment. starting the thing is more pain than it should be for now, especially when you want to use the interesting part (the metagui that can present a random cl-perec ER model). > + To what extent is your machinery more fine-grained? Can you select which > special variables are captured and which aren't? Or do you mean something > else here? it's basically a generic method called for each component in the component path to the root, in a definite order. so you can bind whatever you want in :around methods... of course it means that it's more trouble to rebind variables with this infrastructure than it would be with a dedicated dynamic environment support. but on the other hand we can run code if needed, as opposed to simply reinstating special bindings. and also it's a specialized infrastructure related to components/gui's, nothing generally usable. btw, i think the generic solution to this problem would be to have continuations (either delimited or not) with dynamic-wind support (e.g. as in scheme). for me anything else feels as a specific solution given to a certain use-case. in fact if i really needed this generic language feature, then i would implement closure based CPS in cl-delico (it only has an interpreter for now) and add dynamic-wind support to it. so, to sum up my current state of mind: i'd implement layer instance modification using a specialized cloning (random sideffect: much faster slot access on layers); do our specialized one-shot continuations using some light macrology (as currently done); and if i ever wanted to have all this in a generic way, then i'd extend cl-delico with dynamic-wind. but i'm right before falling asleep, so... :) -- attila From drewc at tech.coop Sat Sep 27 21:05:46 2008 From: drewc at tech.coop (Drew Crampsie) Date: Sat, 27 Sep 2008 14:05:46 -0700 Subject: [closer-devel] Contextl patch: make ensure-layered-method work with function objects as well as names. Message-ID: Hello, In lol i use ensure-layered-method directly on generic functions. I've been using this modified version of ensure-layered-method and thought i'd try and sneak it in :). (defun ensure-layered-method (layered-function-designator lambda-expression &key (layered-function (if (functionp layered-function-designator) layered-function-designator (fdefinition (lf-definer-name layered-function-designator)))) #-(or allegro clisp cmu ecl mcl openmcl) (method-class (generic-function-method-class layered-function)) (in-layer 't) (qualifiers ()) (lambda-list (cadr lambda-expression)) (specializers (required-args lambda-list (constantly (find-class 't))))) (let ((layer-arg (gensym "LAYER-ARG-"))) (destructuring-bind (lambda (&rest args) &body body) lambda-expression (unless (eq lambda 'lambda) (error "Incorrect lambda expression: ~S." lambda-expression)) (ensure-method layered-function `(lambda (,layer-arg , at args) , at body) #-(or allegro clisp cmu ecl mcl openmcl) :method-class #-(or allegro clisp cmu ecl mcl openmcl) method-class :qualifiers qualifiers :lambda-list `(,layer-arg , at lambda-list) :specializers (cons (find-layer-class in-layer) specializers))))) Cheers, drewc From pc at p-cos.net Mon Sep 29 13:35:03 2008 From: pc at p-cos.net (Pascal Costanza) Date: Mon, 29 Sep 2008 15:35:03 +0200 Subject: [closer-devel] Contextl patch: make ensure-layered-method work with function objects as well as names. In-Reply-To: References: Message-ID: <3F4CC663-1D02-4398-BB63-215CFDA6FF96@p-cos.net> Hi Drew, Thanks a lot for this patch, this is indeed an improvement. I will include it in the repository ASAP. Best, Pascal On 27 Sep 2008, at 23:05, Drew Crampsie wrote: > Hello, > > In lol i use ensure-layered-method directly on generic functions. I've > been using this modified version of ensure-layered-method and thought > i'd try and sneak it in :). > > (defun ensure-layered-method > (layered-function-designator > lambda-expression > &key > (layered-function > (if (functionp layered-function-designator) > layered-function-designator > (fdefinition (lf-definer-name layered-function-designator)))) > #-(or allegro clisp cmu ecl mcl openmcl) > (method-class > (generic-function-method-class > layered-function)) > (in-layer 't) > (qualifiers ()) > (lambda-list (cadr lambda-expression)) > (specializers (required-args lambda-list (constantly (find- > class 't))))) > (let ((layer-arg (gensym "LAYER-ARG-"))) > (destructuring-bind > (lambda (&rest args) &body body) > lambda-expression > (unless (eq lambda 'lambda) > (error "Incorrect lambda expression: ~S." lambda-expression)) > (ensure-method layered-function > `(lambda (,layer-arg , at args) , at body) > #-(or allegro clisp cmu ecl mcl openmcl) :method- > class > #-(or allegro clisp cmu ecl mcl openmcl) method- > class > :qualifiers qualifiers > :lambda-list `(,layer-arg , at lambda-list) > :specializers (cons (find-layer-class in-layer) > specializers))))) > > Cheers, > > drewc > _______________________________________________ > closer-devel mailing list > closer-devel at common-lisp.net > http://common-lisp.net/cgi-bin/mailman/listinfo/closer-devel -- Pascal Costanza, mailto:pc at p-cos.net, http://p-cos.net Vrije Universiteit Brussel, Programming Technology Lab Pleinlaan 2, B-1050 Brussel, Belgium