Hi all,
instfilters and -guards are great features in XOTcl. Nevertheless there is room for improvement...
In 99% of the cases one (I at least) creates a filter that needs to be triggered only at a certain method. Even if one has several methods to intercept, it is often easier to create separate methods and use guards to trigger them. Guards are great, but the overall picture of the code gets overly complicated in such cases. Therefore I'd like to propose an argument "-methods" to the filter command, that tells the filter to only be triggered on execution of the methods in the corresponding list:
Class A ... A instproc do1 {} ... A instproc do2 {} ... A instproc do3 {} ...
A instproc do1Filter {} ...
# trigger only at do1 A instfilter do1Filter -methods do1 ;# or -methods {do1 do3}
# rather than A instfilter do1Filter A instfilterguard do1 {[string eq [self calledproc] do1]}
Is such a feature already planned? If not, is there anything that speaks against it?
Dear Eckhard,
Eckhard Lehmann schrieb:
In 99% of the cases one (I at least) creates a filter that needs to be triggered only at a certain method.
The more efficient approach for just intercepting a single method is a mixin. The purpose of the mixins is intercept one or more known methods, the strength of the filters is to execpt all methods. This can be certainly restricted by the guards, but there is a performance penalty in such cases.
Class A ... A instproc do1 {} ... A instproc do2 {} ... A instproc do3 {} ...
A instproc do1Filter {} ...
# trigger only at do1 A instfilter do1Filter -methods do1 ;# or -methods {do1 do3}
well, note that "instfilter" accepts a list of filters (with potential guards)
# rather than A instfilter do1Filter A instfilterguard do1 {[string eq [self calledproc] do1]}
You can define the guard as well at the registraton of a filter, so there is no need for two separate statements.
A instfilter { {do1Filter -guard {[self calledproc] eq "do1"}} }
It should be possible to create a different front-end in tcl, to provide more syntactical sugar and create the guarding expression on the fly:
proc mk_guard args { for {set i 0} {$i < [llength $args]} {incr i} { if {[lindex $args $i] eq "-methods"} { puts stderr M incr i set clause [list] foreach proc_name [lindex $args $i] { lappend clause "[self calledproc] eq "$proc_name"" } lappend guards [join $clause ||] } } return [join $guards &&] }
The interceptor via mixin could be done like the following
A instmixin [Class new -instproc do1 args {puts hi; next}]
Is such a feature already planned? If not, is there anything that speaks against it?
the major argument against it is not to bloat the language with a subset of its functionality.
However, can you tell more about your use-cases?
I was thinking a few times about providing interceptors for single methods, similar to the method combinator :around in CLOS.
http://www.aiai.ed.ac.uk/~jeff/clos-guide.html
This approach could allow to assign something like the filter to a single method of a single class. The advantage would be to no search and testing to filter away the unwanted filter class, but stick this to a method. The approach could fit nicely into the method-slots (in the pipe for 2.0) and could server as a generalization of the current pre and post conditions in XOTcl.
-gustaf neumann
Dear Eckhard,
Eckhard Lehmann schrieb:
One thing comes to mind since I play around with Tclhttpd and a persistency framework: Tclhttpd maintains sessions as safe slave interpreters. These interpreters must know about persistency objects in the server, so it is necessary that
- whenever a persistency object is created, a command alias for it
must be created in certain sessions (interpreters)
- whenever a session is created, certain persistency objects must be
"informed" (-> a command alias for them must be created in the new interpreter).
- whenever a session is destroyed, it's alias must be removed from all
persistency objects that contain it.
i would not recommend to use method combinators or filters for this kind of problem: This problem looks to me like an perfect example for metaclasses.
Meta-classes allow to create special kinds of classes. Sometimes you would like to have PersistentClasses, sometimes RemoteClasses, or LoggedClasses, etc. One can certainly use object or class mixins as well to mix the feature "persistency" into one or several classes. The mixin approach has advantages for finer-grained control, but i doubt that you will need it for e.g. session management.
So, for your problem, define a meta-class for classes with persistant objects and overwrite on the class level the methods "create" and "instdestroy". The same can be done with the Session class as well. I have not looked at the session model of TclHttpd, but from your specification, the class structure can look like the code below. The script produces the following output:
creating object p1 of class ::Person ... create an alias for p1 creating session s1 ... inform instances of ::Person creating object p1 of class ::Person ... create an alias for p1 creating object e1 of class ::Employee ... create an alias for e1 creating session s2 ... inform instances of ::Employee ::Person deleting session ::s2 deleting session ::s1 object ::e1 destroy ... delete alias for ::e1 object ::p1 destroy ... delete alias for ::p1
Hope, this helps. -gustaf neumann
############################################## package require XOTcl namespace import -force ::xotcl::*
Class PersistentClass -superclass Class PersistentClass instproc create {name args} { puts stderr "creating object $name of class [self]" puts stderr "... create an alias for $name" next } PersistentClass instproc instdestroy {name} { puts stderr "object $name destroy" puts stderr "... delete alias for $name" next }
Class Session Session proc create {name args} { puts stderr "creating session $name" puts stderr "... inform instances of [PersistentClass info instances]" next } Session proc instdestroy {name} { puts stderr "deleting session $name" next }
PersistentClass Person Person p1
Session s1
Person p1 PersistentClass Employee -superclass Person Employee e1
Session s2
s2 destroy s1 destroy
Gustaf Neumann schrieb:
So, for your problem, define a meta-class for classes with persistant objects and overwrite on the class level the methods "create" and "instdestroy". The same can be done with the Session class as well. I have not looked at the session model of TclHttpd, but from your specification, the class structure can look like the code below. The script produces the following output:
Actually I am using meta classes already, but not for this kind of behaviour. It's that only some persistency objects should be available in some sessions, not all of them in all sessions - but other objects should be in all sessions. You certainly don't want to have all of your user info appear in someone else's session while you are logged in on the server ;-). Anyway, thanks for your kind help!
BTW, have you or somebody else already considered to make an XOTcl implementation for Jacl (Tcl on Java)?