let us say that I have a namespace. I want to find all of the namespace procs.
For example,
let us say that I have this code:
namespace eval foo {
proc me {} { puts "yey!" }
proc moo {} { puts "ney!" }
}
puts [ getAllNamespaceProcs foo ] ; # getAllNamespaceProcs is what I do not know how to do
This should yield:
> { me moo }
Thanks.
The info procs command can be told what namespace to look in:
info procs ::foo::*
This will yield ::foo::me ::foo::moo (or the other way round; lsort it if you care) and you can filter that (e.g., with lmap and namespace tail) if you want to get the result that you mention.
Related
I have some generic procedure. I would like this procedure to be able to get the name of the namespace and names of the procedures within the namespace where this procedure is called.
I have tried following code:
proc register {} {
puts [info procs]
puts [namespace current]
}
namespace eval Foo {
proc bar {} {
puts bar
}
proc _baz {} {
puts baz
}
register
}
However, this prints results for the namespace where register is defined, not for the namespace where it is executed. It looks like there are no dedicated commands for these tasks or at least these are not info or namespace commands.
To get information about the calling context, use uplevel:
proc register {} {
puts [uplevel 1 [list info procs]]
puts [uplevel 1 [list namespace current]]
}
I have a series of Tcl scripts which are being executed in an interpreter (Cadence Innovus). I want a way to group commands and execute them with a single call. Functionally I can achieve this by writing each group of commands in a separate file and calling source <group_file_name>. However it is inconvenient to define so many files.
I have tried to do this with:
proc {} {
commands...
}
This doesn't give me the functionality I need though. I believe it executes the commands in a lower namespace and the variables that are set do not remain.
Is there a way to get this functionality (a single file with callable functions), but that execute in the same namespace?
Well, you can always use uplevel or namespace eval inside that procedure to change the current namespace. If you use uplevel, you would do this:
proc foo {} {
uplevel 1 {
TheFirstCommand
TheSecondCommand
TheThirdCommand
}
}
With namespace eval, you might instead do this:
proc foo {} {
namespace eval ::theTargetNamespace {
TheFirstCommand
TheSecondCommand
TheThirdCommand
}
}
Things get a bit more complicated if you're wanting to use local variables with the scope-changers, but the principle for how to manage things is about the same whichever mechanism you use.
proc foo {} {
set a [uplevel 1 { TheFirstCommand }]
set b [uplevel 1 { TheSecondCommand }]
# Dynamically-generate the script to run; it's trivial code generation
uplevel 1 [list TheThirdCommand $a $b]
}
Switching to namespace eval is pretty much a drop-in replacement.
Consider a library structured like this:
package provide ::mylib 1.0
namespace eval ::mylib {
namespace export f
proc f { action } {
# pass action around
g $action
}
proc g { action } {
eval $action
}
}
If I try to use it like this, it won't work:
....
namespace eval ::user {
set x 10
::mylib::f { puts $x }
}
The reason is that $x is not known in mylib. I can fix it like this:
namespace eval ::user {
set x 10
::mylib::f { puts $::user::x }
}
This works, but qualifying each variable in the argument to ::mylib::f is awkward. Another possibility is to wrap the code inside another namespace eval:
namespace eval ::user {
set x 10
::mylib::f { namespace eval { puts $x } }
}
Better, but still ugly. If it were Ruby or Perl, I would simply pass a closure to ::mylib::f. What is the best practice in Tcl?
BTW, I'm currently on Tcl 8.3, but hope to have the possibility to upgrade to a newer version soon, so solution in terms of 8.3 AND more recent versions are wellcome.
tl;dr version: namespace code
The namespace code command is intended for this situation. You pass it the script that you want to be encapsulated, and it hands you back a version that has magic in it so that it handles being called from anywhere. Here's how you might use it.
namespace eval ::user {
variable x 10
::mylib::f [namespace code { puts $x }]
}
Internally, it uses namespace inscope to do this. You're recommended to not use that directly; namespace code is the convenient way of doing this.
Note that it even works if the callback site passes arguments to it, so long as that site is doing:
eval $callback [list "the argument is this"]
(In fact, in 8.3 the eval isn't necessary because of a gross hack in unknown, but please do it the way I recommend above because we took that hack out in later versions. It was pretty awful.)
Basically the problem is to execute Tcl code defined in one namespace, using calls to functions in that namespace, in an eval inside another namespace.
The following code works fine:
namespace eval ::eggs {
namespace export e1 eeval
proc e1 {} { puts pe1 }
proc eeval body { puts "in cb enter"; eval $body; puts "in cb exit" }
}
namespace import ::eggs::*
namespace eval ::spam {
namespace export s1 scall
proc scb {} { puts pscb }
proc scall {} { puts "in call enter"; eeval {::spam::scb}; puts "in call exit" }
e1
scall
}
namespace import ::spam::*
and prints:
% % % % % % pe1
in call enter
in cb enter
pscb
in cb exit
in call exit
Now I want to replace the ::spam::scb with a plain scb. I would trade in a wrapper for eeval.
My use case:
The namespace eggs is a very basic library for regression testing. The namespace spam is a small library implementing nice to have functions. They shall be tested upon reload. For this scall is called and uses a special test function in eggs called eeval.
The eeval is the unit test. For convenience and "do-not-repeat-yourself" reasons I'd like to not have to use the fully qualified namespace name of any function defined in spam.
Ideally scall would look like this:
proc scall {} { puts "in call enter"; eeval {scb}; puts "in call exit" }
However, during execution the eval in ::eggs::eeval does not know where to find scb. Since eggs is just a test library I cannot import the spam namespace.
Is there any way one could e.g. devise a wrapper for e.g. eeval to make it run in the other namespace?
If you're going to pass the code to eval (possibly appending arguments) then the simplest method to generate the callback script is with namespace code:
eeval [namespace code {scb}]
That generates all the wrapping code to ensure that things work correctly, including handling all sorts of cases you've not dealt with:
% namespace eval boo {
puts [namespace code {foo bar}]
}
::namespace inscope ::boo {foo bar}
However, if you're doing the callback immediately then the most common approach is not the above, but rather to use uplevel 1 to do the callback:
proc eeval body {
puts "in cb enter"
uplevel 1 $body
puts "in cb exit"
}
This has the advantage that the called-back code really is in the stack context of the caller, allowing it to do useful things like access local variables. Since the code is running in the same context that you define it[*], it's fine using that for resolving command names.
[*] That's a big fat lie — Tcl's semantics are rather more complex than that — but everything works like what I've said is true.
namespace current is the DRYer you're probably looking for.
namespace eval ::spam {
proc scall {} {
puts {in call 2 enter}
eeval [namespace current]::scb
puts {in call 2 exit}
}
}
Or pass the current namespace to the eeval proc
proc ::eggs::eeval {body {namespace ""}} {
puts "in cb enter"
if {$namespace == ""} {
eval $body
} else {
namespace eval $namespace $body
}
puts "in cb exit"
}
proc ::spam::scall {} {
puts "in call 3 enter"
eeval scb [namespace current]
puts "in call 3 exit"
}
Are there any packages or any specific way to support function or procedure overloading in TCL??
This is my scenario. I need to write a generic procedure that accepts two or 3 files, wherein I may or may not have the third file (File3)
proc fun { File1 File2 File3 }
{
}
proc fun { File1 File2 }
{
}
There is no overriding in tcl. The second declaration will just replace the first one.
But you handle it with a single procedure. There are two ways at least:
1) Specify the last argument with its default value. Then it will be optional when you calls the function.
proc fun { file1 file2 {file3 ""} } {
if {$file3 != ""} {
# the fun was called with 3rd argument
}
}
2) Use the special argument args, which will contain all arguments as a list. And then analyze the number of arguments actually passed to.
proc fun { args } {
if {[llength $args] == 3} {
# the fun was called with 3rd argument
}
}
Tcl doesn't really support procedure overloading, which makes sense when you consider that it doesn't really have types, per se. Everything is a string that can, depending on value, be interpreted as other types (int, list, etc).
If you can describe what it is you're trying to accomplish (why you think you need overloading), we might be able to make a recommendation about how to accomplish it.
Given the edit to your question, there's a couple different ways to go about it. GrAnd has shown 2 of them. A third, and one I'm a fan of, is to use information specifically about how the command was called:
proc fun { File1 File2 {File3 ""}} { ;# file3 has a default
if {[llength [info level 0]] == 3} { ;# we were called with 2 arguments
;# (proc name is included in [info level 0])
# do what you need to do if called as [fun 1 2]
} else { ;# called with 3 arguments
# do what you need to do if called as [fun 1 2 3]
}
}
Here is an example to hack puts, using a namespace to hide puts and :: to access built-in:
namespace eval newNameSpace {
proc puts {arg} {
set tx "ADDED:: $arg"
::puts $tx
}
puts 102
}
Another way, you can do this:
proc example {
-file1:required
-file1:required
{-file3 ""}
} {
if {$file3 ne ""} {
#Do something ...
}
}
when you call the proc
example -fiel1 info -file2 info2