问题
To enhance the functionality of a tcl/tk
program, I'd like to re-implement one of it's original (namespaced) functions. The new implementation should call the original implementation for the core functionality, and add some nifty stuff around.
This is documented quite well using tcl's rename command.
To keep things as modular as possible, I would like to put my new functionality into a separate namespace.
I would also like to avoid adding things to the original namespace of the toobe-enhanced function.
So the plan was:
- rename
::simple::function
to::enhanced::simple_function
- create a new
::simple::function
that calls::enhanced::simple_function
this works all very well, unless the original function uses other members of its namespace without fully qualifying them.
Here's an example:
namespace eval ::foospace:: {
proc bar {a} { puts $a }
proc foo {X} { bar "foospace:foo:: $X" }
}
## test original function
::foospace::foo "hello world"
## shadowing the original ::foospace::foo into a new namespace
rename ::foospace::foo ::barspace::foo
proc foospace::foo {x} {
puts "DEBUG: $x"
::barspace::foo "$x"
}
# test enhanced function
::foospace::foo "goodbye moon"
This gives me:
invalid command name "bar" while executing "bar "foospace:foo:: $X" "
If the original ::foospace::foo
uses ::foospace::bar
instead of bar
, everything works fine.
Unfortunately I cannot "fix" the original implementation.
It would also work if i just renamed ::foospace::foo
to ::foospace::foo_bar
instead of ::barspace::foo
but this means touching a namespace that does not belong me (which I would like to avoid).
Is there a way to rename my original function into a new namespace and allow unqualified function names in the original function?
回答1:
One of the things about procedures and namespaces is that the current namespace for the purpose of command and variable resolution for a procedure is determined by the namespace that the procedure is placed in. This means that when you rename
the procedure into another namespace, you change how it behaves. You mostly get away with it when the majority of commands are in the global namespace (as that is where Tcl searches if it can't find the commands in the current namespace) but it can have quite a profound effect. It's possible to insulate the code from the effects of being moved around (e.g., using fully-qualified command names and namespace upvar
instead of variable
) but most people don't bother as it is a colossal pain that is hardly ever needed.
You're recommended to simply never rename things across namespaces. It causes trouble that is hard to debug (I can explain them on a case-by-case basis); the issues you've seen are symptoms of this, and no, you cannot rename my original function into a new namespace and allow unqualified function names in the original function.
There are other techniques. Command execution traces might be suitable, as might using namespace imports. Or it might be that you're trying to do a pseudo-object system: if that's the case, you should switch to one of the real ones as they handle many issues you haven't thought of. (My favourite is TclOO, which ships as part of Tcl 8.6, but then I wrote it so I'm more than a bit biased!) Using a real object system makes switching things around quite a lot simpler.
来源:https://stackoverflow.com/questions/33847898/renaming-command-into-different-namespace