[closer-devel] slots on layers

Pascal Costanza pc at p-cos.net
Wed Aug 20 10:38:27 UTC 2008


Hi Atilla,

Thanks a lot for your question and detailed explanation of your use  
case. Such feedback is very helpful in understanding the limitations  
of ContextL.

I have a question, see a problem with your suggested approach, and  
think there is already a way in ContextL to achieve what you want.  
However, I am not 100% sure, so please don't consider this as the  
final word in this regard, but rather as a starting point for  
continuing the discussion.

The question: I understand that you want to be able to reuse the state  
of layer-specific slots from deactivated layers when you activate such  
layers again. However, I don't quite understand how you expect to  
activate that specific layer instance. Do you expect to be able to  
inquire about which layers are currently active, and then pick out the  
one you're interested in? The problem here is that in the general  
case, the one layer you're interested in is somewhere in the list of  
active layers, and not necessarily at the start or the end of the  
list. So what criteria do you want to use to pick out the one specific  
layer you're interested in? Or do you just want to refer to a layer  
name? (This may seem the obvious way, but actually makes it harder for  
me to understand what you really want/need, that's why I'm asking the  
question...)

The problem (probably related to the question): When you pick out the  
class prototype of the currently active layer combination (!), it is  
an instance of an automatically generated class that hass all the  
active layers as superclasses. So, for example, if layers l1, l2 and  
l3 are active in that order, the class prototype is an instance of a  
class %l123 that has l1, l2 and l3 as superclasses. Now, assume that  
you are interested in the layer-specific state of l3, so you want to  
pick out an instance that represents that state. It would have to be  
an instance of the class %l123 as well, in order to ensure that  
context-oriented dispatch works correctly. However, it could be that  
in a new situation where you want to activate l3 again, there is a  
different set of other layers currently active, say l2 and l4. The  
eventual class prototype that represents the set of active layers  
after reactivation of l3 should now be an instance of a class %l243,  
so a class different from %l123. This automatically means that you  
_cannot_ reuse that old instance of %l123. So in other words, reusing  
the same class prototype from a previous activation state is _not_ a  
good idea (unless you perform a change-class on that instance, but I  
have strong reservations with regard to my willingness to deal with  
the complexities that would arise from this ;).

An alternative solution: Why don't you just use layer inheritance? You  
can then use layer-specific slots (whether they are :special or not)  
in sublayers of the respective layers you are interested in.

As an example:

(deflayer foo3)

(deflayer sub1foo3 (foo3)
   ((some-slot :initform 2)))

(deflayer sub2foo3 (foo3)
   ((some-slot :initform 3)))

...etc., for as many sublayers as you want. The idea here is that you  
use layers as prototypical objects (in the sense of languages like  
Self or JavaScript) which can directly inherit from each other. You  
then "just" have to ensure that you activate the correct sublayers for  
the various contexts you're interested in. It should actually also be  
possible to use anonymous layers which are generated at runtime  
(although that part of the ContextL API has not seen extensive testing  
in real-world use so far, to the best of my knowledge).

Would that get you closer (ha!) to a working solution for your problem?

Best,
Pascal

P.S.: I don't want to avoid changes to ContextL, it's just that I want  
to make sure that changes to ContextL fit well with the rest of the  
design of ContextL, that's why I'm yet hesitating to adopt your  
suggested solution. Again, thanks a lot for your feedback, it is very  
valuable!

On 18 Aug 2008, at 23:06, Attila Lendvai wrote:

> dear list,
>
> from time to time we are returning to an important use-case that can't
> (?) be done using contextl currently. what we need is slots on the
> layer prototype that keep the expected semantics when layers are
> restored using (current-layer-context) and (funcall-with-layer-context
> ...).
>
> the problem is that if a non-special slot is defined for a layer, then
> it's shared between all threads (in the slot of the single cached
> prototype). but :special t slots won't work as expected either,
> because they store their values in special bindings which are lost
> when going through c-l-c/f-w-l-c.
>
> our real-world use-case is this: we have a bunch of factory methods
> that build up a gui component hierarchy. this algorithm is driven by
> the metadata of the data model of the application. this metadata has
> entities, typed properties, associations, etc, so if you define a data
> model then in return you get a 90% gui that can be used to navigate
> and edit the data.
>
> to fill in the remaining 10% for each project, we need to customize
> this algorithm (a bunch of layered methods), which is achived using
> layers. it serves well most of the time, but often at the entry points
> of this algorithm we need to store some lexically available
> information in the layer instance to make it accessible deep inside
> the recursive algorithm where the customized methods of the layer get
> called.
>
> the problem: the gui built by this algorithm is huge/infinite in
> various directions, so it's built lazily as the data graph is
> navigated. when the user clicks something in the browser, the server
> potentially needs to extend the component graph by invoking some
> closures. we restore the layer context when those closures are called,
> but the slots of the layers are not restored.
>
> the current contextl implementation tries hard to speed up layer
> activation. for us a much simpler implementation would suffice: the
> layer instance would not only be a prototype but a full instance which
> is instantiated at each layer activation/deactivation and the value of
> the remained slots copied over from the parent layer instance. the
> instance could be directly rebound in the *layer* variable. also note
> that this alternative implementation could fall back to using
> prototypes when the layer has no slots (which is probably most of
> the deployed usages. users, speak up! :)
>
> we understand that this can be much slower when it comes to changing
> the current effective layer, but we are not sure if this really counts
> when it comes to the overall application performance. we don't know
> how others are using contextl but in our usages the number of changes
> to the active layers is negligable compared to the rest of the
> runtime.
>
> any thoughts?
>
> --
> attila
>
> PS: a simple example:
>
> CONTEXTL> (deflayer foo2 ()
>            ((slot :initform 42 :accessor slot- 
> of :initarg :slot :special t)))
> CONTEXTL> (mapcar #'slot-of
>                  (with-active-layers ((foo2 :slot 2))
>                    (list (layer-context-prototype (current-layer- 
> context))
>                          (with-active-layers ((foo2 :slot 3))
>                            (layer-context-prototype
> (current-layer-context))))))
>
> it returns (42 42) while we expect here to get (2 3). this effectively
> means that we can't reinstate layer contexts that have slots.
> _______________________________________________
> 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









More information about the closer-devel mailing list