I'm trying to implement a hierarchical structure of classes/subclasses objects such as:
|-- Class1 # mainClass
| |-- SubClassA # subClass
| `-- SubClassB # subClass
`-- Class2 # mainClass
|-- SubClassA # subClass
`-- SubClassB # subClass
The main point here is to be able to declare different subclasses having the same name in each main classes (and have their variables independant).
(Note: I'm talking here about hierarchy of classes objects created during execution, not about heritage of different classes.)
Quite not very familiar with some advanced aspects specific to Tcl (namespace, scope...), I tried the following code:
package require Itcl
itcl::class subClass {
variable InternalVariable
constructor {} {
puts "($this) Current namespace : [namespace current]"
puts "($this) InternalVariable scope : [itcl::scope InternalVariable]"
}
}
itcl::class mainClass {
variable SubClassesList
constructor {} {
set SubClassesList {}
puts "($this) current namespace : [namespace current]"
puts "($this) SubClassesList scope : [itcl::scope SubClassesList]"
}
method newSubClass {argName} {
lappend SubClassesList [subClass $argName]
puts "($this) SubClassesList : {$SubClassesList}"
}
}
# Create the two main classes
mainClass Class1
mainClass Class2
# Add some subclasses to Class1 and Class2
Class1 newSubClass SubClassA
Class1 newSubClass SubClassB
Class2 newSubClass SubClassC
Class2 newSubClass SubClassB
which produces an error when creating the second occurence of SubClassB
:
(::Class1) current namespace : ::mainClass
(::Class1) SubClassesList scope : @itcl ::Class1 ::mainClass::SubClassesList
(::Class2) current namespace : ::mainClass
(::Class2) SubClassesList scope : @itcl ::Class2 ::mainClass::SubClassesList
(::mainClass::SubClassA) Current namespace : ::subClass
(::mainClass::SubClassA) InternalVariable scope : @itcl ::mainClass::SubClassA ::subClass::InternalVariable
(::Class1) SubClassesList : {SubClassA}
(::mainClass::SubClassB) Current namespace : ::subClass
(::mainClass::SubClassB) InternalVariable scope : @itcl ::mainClass::SubClassB ::subClass::InternalVariable
(::Class1) SubClassesList : {SubClassA SubClassB}
(::mainClass::SubClassC) Current namespace : ::subClass
(::mainClass::SubClassC) InternalVariable scope : @itcl ::mainClass::SubClassC ::subClass::InternalVariable
(::Class2) SubClassesList : {SubClassC}
command "SubClassB" already exists in namespace "::mainClass"
I'm probably missing a point about classes namespaces because I do not understand how the variable SubClassesList
can have two different scopes but the "same" namespace/name (from debug output).
I tried to create a new namespace in the newSubClass
method but it did not resolve the problem and/or add some inextricable variables namespaces errors...
method newSubClass {argName} {
set SubClassName "[namespace current]::[namespace tail $this]"
puts "($this) SubClassName : $SubClassName"
namespace eval $SubClassName "lappend SubClassesList [subClass $argName]"
puts "($this) SubClassesList : {$SubClassesList}"
}
Any idea to perform such a thing ?
P-S: I used [incr Tcl] to implement classes in my project for compatibility reasons with existing environment but if someone thinks that an other OO implementation would be better/easier, please let me know...
EDIT :
Found a solution by using namespace eval
+ namespace inscope
to create subClass
objects in a new namespace corresponding to mainClass
objects name:
itcl::class mainClass {
variable SubClassesList
constructor {} {
set SubClassesList {}
puts "($this) current namespace : [namespace current]"
puts "($this) SubClassesList scope : [itcl::scope SubClassesList]"
# Create a new namespace corresponding to class name
namespace eval $this {}
}
method newSubClass {argName} {
# Create the subClass object in the $this namespace
lappend SubClassesList [namespace inscope $this subClass $argName]
puts "($this) SubClassesList : {$SubClassesList}"
}
}