Home > Net >  How to create object inside another class in TCL
How to create object inside another class in TCL

Time:09-06

I have two classes

oo::class create Item {
}

oo::class create Builder {
    constructor {} { set my_item [Item new] }
    destructor { send_message info "Builder Destructor" }
}

When I run this on system-console, it says "Invalid command name: Item".

I wonder if the class type Item is not observed by Builder class therefore cannot create an object of type Item when creating the constructor. Am I missing something so I can create a diff-class object inside a class method?

CodePudding user response:

As written, your code works. But if the Item class name is really in another namespace then the Builder class won't look there by default. Same as for any command resolution.

Classes do not pick up the resolution scope of the point where they were defined except for determining what their public name should be (when it isn't already fully qualified, of course). Indeed, at the actual point when you define a constructor the resolution scope is non-trivial (it's technically in a definition scope, which is an enhanced form of namespace eval) and it might well be completely different when that constructor gets called. TclOO is extremely careful about handling of stack frames and resolution scopes.

In short, if you are really doing:

namespace eval ::foo {
    oo::class create Item {
    }
    
    oo::class create Builder {
        constructor {} { set my_item [Item new] }
        destructor { send_message info "Builder Destructor" }
    }
}

then you'll need to do:

namespace eval ::foo {
    oo::class create Item {
    }
    
    oo::class create Builder {
        constructor {} { set my_item [::foo::Item new] }
        destructor { send_message info "Builder Destructor" }
    }
}

Or to adjust the namespace path of the Builder instance prior to making the Item instance. If you do the latter, be aware that the default namespace path of all TclOO objects is non-empty (it's where next and self come from).

CodePudding user response:

Expanding on @Schelte's comment:

# paste your code
# then expand it a bit

% oo::define Builder {variable my_item}
% oo::define Builder {method item {} {return $my_item}}
% set b [Builder new]
::oo::Obj13
% $b item
::oo::Obj14
% info object class [$b item]
::Item
  • Related