potrzebie
potrzebie

Reputation: 1798

The real namespace of a class

Inside a constructor, destructor or method, can I find out what namespace the class was created in, so I can just call card in my other classes instead of hard coding it as blackjack::card?

namespace eval blackjack {

  oo::class create card {
    ...
  }

  oo::class create deck {
    constructor {} {
      my variable cards
      set cards {}
      for {set suit 0} {$suit < 4} {incr suit} {
        for {set value 0} {$value < 13} {incr value} {
          lappend cards [blackjack::card new $suit $value]
        }
      }
    }
    ...
  }

}

Upvotes: 2

Views: 132

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137767

Option 0: Fully-qualified names

You already know this, and it is what I actually do almost always as it's direct and simple. (It's “Option 0” because it un-asks the question.)

Option 1: uplevel

You could do:

lappend cards [uplevel 1 [list card new $suit $value]]

But that depends on the deck new being called from the right namespace.

Option 2: Class name surgery

If we assume that the two classes are in the same namespace:

constructor {} {
    set cardClass [namespace qualifiers [self class]]::card
    # ...
        lappend cards [$cardClass new $suit $value]
    # ...
}

Option 3: Extending the object's namespace path

If you add to the object's path (NB: must be done on a per-object basis in the constructor right now) then you can refer to the other class simply:

constructor {} {
    namespace path [list {*}[namespace path] ::blackjack]
    # ...
        lappend cards [card new $suit $value]
    # ...
}

The main thing to watch out here is that TclOO sets a non-trivial default namespace path (where do you think that next and self come from?)

Option 4: Making a command link

You have another option, and that is to use namespace export and namespace import to make a command link.

First, export the relevant classes from the ::blackjack namespace:

namespace eval ::blackjack {
    namespace export card;   # You probably want to export “deck” as well

    # ...
}

Then, do the import in the constructor:

constructor {} {
    namespace import ::blackjack::card
    # ...
        lappend cards [card new $suit $value]
    # ...
}

Option 5: Make a special subclass in the deck instance

This one is tricky!

constructor {} {
    oo::class create card {superclass ::blackjack::card}
    # ...
        lappend cards [card new $suit $value]
    # ...
}

This also means that the cards will be automatically deleted when the deck goes away; you don't need to destroy them in the destructor (because their actual class will be automatically removed, and that kills the instances). That might or might not be what you need. (It does make for a good way of modeling a UML composition relation; TDBC uses a variation on this internally to associate statements with connections and result sets with statements.)

Upvotes: 4

Related Questions