Hello
I'm working on real-life application, which controls some hardware devices throw network protocol.
For now this application consist of several instances of some objects, which implements FSM (finite state machines) of hardware devices. Now it is implemented using Itcl, but I need possibility to change fsm states and implementation without restarting application. Itcl does not allow me to do this, so I decided to switch to XOTcl.
I split my application in several source files. Each of files implements one of fsm's or helper functions, and when I need to change logic of work, i simply source all files.
There are several problems with this: 1) when I execute command Class Some, previous instance of this class deleted, and all objects move to ::Object class. This problem I solve by using filter for create command on ::Object (idea stolen from recoverypoint class :)) ). But with that second problem arrives: 2) when some instproc used as a filter, and redefined, it's filter become inactive. (so first problem arrives again, when I source recover.tcl which has recoverfilter definition) after setting filter again, all works as expected
Hope for your help :))
Example code: ----------------- a.xotcl ----------------- #!/usr/local/bin/tclsh8.2
package require XOTcl
Object instproc filter {args} { puts "filter: [self] [[self] info calledproc]" next }
Object filter filter
puts "Object test" Object test puts "test set a a" test set a a
puts "Object instproc filter" Object instproc filter {args} { puts "new filter: [self] [[self] info calledproc]" next }
puts "test set a a" test set a a
puts "Object filter filter" Object filter filter
puts "test set a a" test set a a ----------------------------------------- Result:
Object test filter: ::Object test filter: ::Object create test set a a filter: ::test set Object instproc filter filter: ::Object instproc test set a a ^^^^^^^^^^^^^^^ unfiltered Object filter filter test set a a new filter: ::test set new filter: ::@ destroy new filter: ::test destroy
Hi,
On Tue, 26 Dec 2000 seva@design.kiev.ua wrote:
I split my application in several source files. Each of files implements one of fsm's or helper functions, and when I need to change logic of work, i simply source all files.
There are several problems with this:
- when I execute command Class Some, previous instance of this
class deleted, and all objects move to ::Object class.
this behavior is intended: from a "programming language point of view" you can not predict whether a destroyed class is going to be redefined or not. There could be another class with the same name, but with different semantics.
In cases like your application, that require a class redefinition, there are several ways to tell the language to behave like this:
- you can use the filter, as you have done to overload create. - you can use a subclass or a mixin to change create bahavior - or you use introspection to find out which instances are currently there and re-class these instances after sourcing to the new classes (same-named) classes
Probably a combination would work here, like a instmixin on object that checks whether a class-to-be-created exists. If yes all instances are stored in a variable. After create, the instances are re-classed back to the old class.
Or you build an instmixin tht simply does not execute the "create" on certain existing classes?
It depends on your application case which solution is the best here ...
This problem I solve by using filter for create command on ::Object (idea
stolen from recoverypoint class :)) ). But with that second problem arrives: 2) when some instproc used as a filter, and redefined, it's filter become inactive. (so first problem arrives again, when I source recover.tcl which has recoverfilter definition) after setting filter again, all works as expected
for the same reason as we have to re-class exisiting instances, we have to set the filters to an empty list, when the method is redefined (the same is done for mixins, when the class is redefined). E.g., we can not say that in any case with "Object instproc filter" the same method is defined. But again you can easily change this behavior for certain cases with a filter or instmixin or a subclass of Object, by redefining "mixin", "instmixin", "filter", etc. so that they check whether a certain filter, mixin, or instmixin is still there. A filter on Object is probably not the best solution here, because it performs the check on every call in the system. This is a heavy performance overhead. Presumably a mixin solution is more well-suited, because it only checks for certain methods and can be used object-specifically.
In your example code a "mixin" on "Class", that just checks the Class->create method could be sufficient.
Hope this helps,
Uwe
-- Uwe Zdun Specification of Software Systems, University of Essen Phone: +49 201 81 00 332, Fax: +49 201 81 00 398 zdun@xotcl.org, uwe.zdun@uni-essen.de
On Thu, 28 Dec 2000, Uwe Zdun wrote:
Hi,
On Tue, 26 Dec 2000 seva@design.kiev.ua wrote:
I split my application in several source files. Each of files implements one of fsm's or helper functions, and when I need to change logic of work, i simply source all files.
There are several problems with this:
- when I execute command Class Some, previous instance of this
class deleted, and all objects move to ::Object class.
this behavior is intended: from a "programming language point of view" you can not predict whether a destroyed class is going to be redefined or not. There could be another class with the same name, but with different semantics.
Ok, I agree with that point :)) (But does'nt like it too much :)) )
In cases like your application, that require a class redefinition, there are several ways to tell the language to behave like this:
- you can use the filter, as you have done to overload create.
- you can use a subclass or a mixin to change create bahavior
- or you use introspection to find out which instances are currently there and re-class these instances after sourcing to the new classes (same-named) classes
Probably a combination would work here, like a instmixin on object that checks whether a class-to-be-created exists. If yes all instances are stored in a variable. After create, the instances are re-classed back to the old class.
Or you build an instmixin tht simply does not execute the "create" on certain existing classes?
Yes, it is a solution which I use now. But probably I switch to instmixin with create overloaded.
It depends on your application case which solution is the best here ...
This problem I solve by using filter for create command on ::Object (idea
stolen from recoverypoint class :)) ). But with that second problem arrives: 2) when some instproc used as a filter, and redefined, it's filter become inactive. (so first problem arrives again, when I source recover.tcl which has recoverfilter definition) after setting filter again, all works as expected
for the same reason as we have to re-class exisiting instances, we have to set the filters to an empty list, when the method is redefined (the same is done for mixins, when the class is redefined). E.g., we can not say that in any case with "Object instproc filter" the same method is defined. But again you can easily change this behavior for certain cases with a filter or instmixin or a subclass of Object, by redefining "mixin", "instmixin", "filter", etc. so that they check whether a certain filter, mixin, or instmixin is still there. A filter on Object is probably not the best solution here, because it performs the check on every call in the system. This is a heavy performance overhead. Presumably a mixin solution is more well-suited, because it only checks for certain methods and can be used object-specifically.
In your example code a "mixin" on "Class", that just checks the Class->create method could be sufficient.
Ok, I tried another test case. Class A with two filters f1 and f2
Class A
A instproc f1 {args} { puts ">> filter f1" next }
A instproc f2 {args} { puts ">> filter f2" next }
A filter {f1 f2}
Instance of this class
A a
anything works ok: a set b 1
filter f1 filter f2
redefine f2:
A instproc f2 {args} { puts ">> new filter f2" next }
still 2 filters: A info filter f1 f2
test: a set b 1
filter f1
interesting: A info filter f1
seems like ok, but when I put it in file and execute it, I get: a set b 1
filter f1 filter f2
A filters: f1 f2 a set b 1
filter f1 filter f2
redefine f2 a set b 1
filter f1
while executing "a set b 1" (file "./a.tcl" line 35)
filter f1
Contents of file: =================================================== #!/usr/local/bin/tclsh8.2
package require XOTcl
Class A
A instproc f1 {args} { puts ">> filter f1" next }
A instproc f2 {args} { puts ">> filter f2" next }
A a A filter {f1 f2}
puts "a set b 1" a set b 1
puts "A filters: [A info filter]"
puts "a set b 1" a set b 1 puts "redefine f2"
A instproc f2 {args} { puts ">> new filter f2" next }
puts "a set b 1" a set b 1 puts "A filters: [A info filter]" puts "a set b 1" a set b 1 puts "A filters: [A info filter]"
============================================= seems that first execution of a filter after redefining leads to error
"seva" == seva seva@design.kiev.ua writes:
On Tue, 26 Dec 2000 seva@design.kiev.ua wrote:
I split my application in several source files. Each of files implements one of fsm's or helper functions, and when I need to change logic of work, i simply source all files.
There are several problems with this:
- when I execute command Class Some, previous instance of this
class deleted, and all objects move to ::Object class.
this behavior is intended: from a "programming language point of view" you can not predict whether a destroyed class is going to be redefined or not. There could be another class with the same name, but with different semantics.
seva> Ok, I agree with that point :)) (But does'nt like it too much :)) )
We have discussed the redefinition of Classes recently, and we are thinking about ways to improve it. However, for the time being you can use something like the following (take care, this version is very simplistic and assumes that the new class is defined exactly like the original
=============================================================== # The following create method is non-destructive, it lets # exiting classes untouched Class CheckCreate CheckCreate instproc create {cn args} { puts "[self] [self proc] $cn <$args>" if {[[self] isclass $cn]} { puts "Dont redefine $cn, ignore '$args'" } else { next } } #overload create of the Metaclass Class mixin CheckCreate ===============================================================
you can use it later like in the following example: the create method, which is implicitly invoked, does not delete the old class in cases it exists already....
=============================================================== Class A Class B -superclass A B a
foreach i {instances heritage} {puts "$i of B:\t[B info $i]"} puts stderr ============= Class B -superclass A foreach i {instances heritage} {puts "$i of B:\t[B info $i]"} ===============================================================
I would expect that the solution above is quite similar to what you have already achieved via filters....
The redefine problem of the filter method, that you mention in your mail, looks like a bug to me, that we should fix in the next release. In the meantime, you should be able to use something like the following: you can redefine "instproc" to check, whether the new definition of a method is a definition of a filter, and if yes, you can register the filter again automatically. For simplicity, the following piece of code assumes, that the filter is defined in the same class for which it is registered.
========================================================================== # The following instproc method circumvents a bug in XOTcl 0.84 # and earlier Class FilterInstproc FilterInstproc instproc instproc {name args} { set filters [[self] info filter] next if {[lsearch $filters $name]>-1} { puts "redefined filter $name" [self] filter $filters } } # overload insproc Object instmixin FilterInstproc ==========================================================================
with this definition, your example will work as expected.....
best regards
-gustaf neumann