Recently I suggested that it would be interesting if TIP 257 defined a myclass command which an object could use to access its class’s unexported methods and also its class variables. I’ve figured out a remarkably tacky way to do so–it’s so tacky that I’m almost ashamed to describe it.
First, remember that myclass would simply be the class’s own my command aliased into the instance’s namespace. If the instance knew the class’s namespace it could define myclass quite simply using interp alias:
interp alias {} [self namespace]::myclass {} ${classns}::my
Given this, the instance could then declare and use its class’s variables; this is often useful for lookup tables which are static and can be shared by all of the class’s instances:
myclass variable lookupTable
set value $lookupTable($key)
The question is, how can the instance acquire the class’s namespace? One way would be to define an exported class method called namespace, but that affects the class’s public interface, which we don’t want to do. So here’s a dirty trick: we temporarily export the class’s eval method, and use it to query the class’s namespace. We can do this any place in the instance code:
# FIRST, get the class's name
set class [info object class [self]]
# NEXT, export its eval method, making it public.
oo::define $class self.export eval
# NEXT, get the namespace
set classns [$class eval {namespace current}]
# NEXT, unexport its eval method, making it private
oo::define $class self.unexport eval
# NEXT, alias in myclass
interp alias {} [self namespace]::myclass {} ${classns}::my
As I say, I’m almost ashamed of this trick. It’s a very roundabout way to get information the class doesn’t really want me to have; and then, also, it’s rather fragile (at least when applied to classes found in the wild). I’m making a couple of unwarranted assumptions: first, that the class hasn’t redefined eval for its own purposes, so that it no longer does what I think it does, and second, that the class wants eval to be private. Both are just reasonable enough that the corner-cases will catch you unawheres.
In a controlled environment, though, this trick might be worth using. For example, an instance of an igloo::type might conceivable use this trick during its construction…if I can’t figure out an easier way to get the job done.