I am having a package TEX.
package require ABC
package provide TEX 1.0
namespace eval ::65FGA {
}
proc ::65FGA::runSuite {{setupFile ""} args} {
Proc body
proc body
}
I am not getting why namespace with empty braces is used..
It may just be a matter of style:
namespace eval ::my_namespace {}
proc ::my_namespace::procname {} {...}
versus
namespace eval ::my_namespace {
proc procname {} {...}
}
Do you mean that
namespace eval ::65FGA {
}
bit?
This command just creates a namespace "65FGA" and then evaluates an empty string (empty script if this sounds more sensible to you). As a result, the said namespace is created but it does not yet contain anything in it.
In this code, you could remove the command invocation being discussed and it won't affect anything. Hence most probably it serves narrative purpose stating clear that the package is creating the said namespace (which it then populates with at leat one procedure).
UPDATE: Struck through the false statement (thanks to Eric Melski). The namespace must exist, indeed, before an attempt is made to create anything in it (via proc or set commands).
Related
I'm trying to create some read-only variables to use with code evaluated in a safe interp. Using trace, I can generate an error on attempts to set them, but not when using unset:
% set foo bar
bar
% trace add variable foo {unset write} {apply {{var _ op} { error "$var $op trace triggered" }}}
% set foo bar
can't set "foo": foo write trace triggered
% unset foo
%
Indeed, I eventually noticed the documentation even says in passing:
Any errors in unset traces are ignored.
Playing around with different return codes, including custom numbers, they all seem to be ignored. It doesn't trigger an interp bgerror handler either. Is there any other way to raise an error for an attempt to unset a particular variable?
There really isn't. The key problem is that there are times when Tcl is going to unset a variable when that variable really is going to be deleted because its containing structure (a namespace, stack frame or object, and ultimately an interpreter) is also being deleted. The variable is doomed at that point and user code cannot prevent it (except by the horrible approach of never returning from the trace, of course, which infinitely postpones the death and puts everything in a weird state; don't do that). There's simply nowhere to resurrect the variable to. Command deletion traces have the same issue; they too can be firing because their storage is vanishing. (TclOO destructors are a bit more protected against this; they try to not lose errors — there's even pitching them into interp bgerror as a last resort — but still can in some edge cases.)
What's more, there's currently nothing in the API to allow an error message to bubble out of the process of deleting a namespace or call frame. I think that would be fixable (it would require changing some public APIs) but for good reasons I think the deletion would still have to happen, especially for stack frames. Additionally, I'm not sure what should happen when you delete a namespace containing two unset-traced variables whose traces both report errors. What should the error be? I really don't know. (I know that the end result has to be that the namespace is still gone, FWIW, but the details matter and I have no idea what they should be.)
I'm trying to create some read-only variables to use with code evaluated
Schelte and Donal have already offered timely and in-depth feedback. So what comes is meant as a humble addition. Now that one knows that there variables traces are executed after the fact, the below is how I use to mimick read-only (or rather keep-re_setting-to-a-one-time-value) variables using traces (note: as Donal explains, this does not extend to proc-local variables).
The below implementation allows for the following:
namespace eval ::ns2 {}
namespace eval ::ns1 {
readOnly foo 1
readOnly ::ns2::bar 2
readOnly ::faz 3
}
Inspired by variable, but only for one variable-value pair.
proc ::readOnly {var val} {
uplevel [list variable $var $val]
if {![string match "::*" $var]} {
set var [uplevel [list namespace which -variable $var]]
}
# only proceed iff namespace is not under deletion!
if {[namespace exists [namespace qualifiers $var]]} {
set readOnlyHandler {{var val _ _ op} {
if {[namespace exists [namespace qualifiers $var]]} {
if {$op eq "unset"} {
::readOnly $var $val
} else {
set $var $val
}
# optional: use stderr as err-signalling channel?
puts stderr [list $var is read-only]
}
}}
set handlerScript [list apply $readOnlyHandler $var $val]
set traces [trace info variable $var]
set varTrace [list {write unset} $handlerScript]
if {![llength $traces] || $varTrace ni $traces} {
trace add variable $var {*}$varTrace
}
}
}
Some notes:
This is meant to work only for global or otherwise namespaced variables, not for proc-local ones;
It wraps around variable;
[namespace exists ...]: These guards protect from operations when a given parent namespace is currently under deletion (namespace delete ::ns1, or child interp deletion);
In the unset case, the handler script re-adds the trace on the well re-created variable (otherwise, any subsequent write would not be caught anymore.);
[trace info variable ...]: Helps avoid adding redundant traces;
[namespace which -variable]: Makes sure to work on a fully-qualified variable name;
Some final remarks:
Ooo, maybe I can substitute the normal unset for a custom version and
do the checking in it instead of relying on trace
Certainly one option, but it does not give you coverage of the various (indirect) paths of unsetting a variable.
[...] in a safe interp.
You may want to interp alias between a variable in your safe interp to the above readOnly in the parent interp?
This is a simplified case of a problem. I am trying to copy a procedure to a namespace, so that it would be using the namespace own's context. Using import does not work (probably because it just creates aliases) See code below:
proc me_namespace {} {
puts "namespace is:[namespace current]"
puts "called namespace is:[uplevel 1 namespace current ]"
}
namespace eval foo {} {
me_namespace
puts "Now import"
namespace import ::::me_namespace
me_namespace
}
The code output is:
namespace is:::
called namespace is:::foo
Now import
namespace is:::
called namespace is:::foo
namespace is:::foo
Ideally, the proc me_namespace 1st line output, after the copying, should be:
::::me_namespace
Any ideas? The only thing that I can think of is having the procedures definitions be in a file, and then reading the file, and using eval, but I was looking for something more elegant.
The reason that I do not just use uplevel, is that at times (in particular when using variable with uplevel is that the runtime, a times, is far too slow. TCL version is 8.6
Procedures are bound to their containing namespace. Rename the procedure, change its binding. (I hate that!) To recreate a procedure in another namespace, you effectively have to either rename (a move) or to rerun the proc that created the original.
Now, while I'd really recommend looking at using TclOO when you're getting into this sort of thing, you might be able to use a different technique. The namespace upvar command is reasonably fast, and you might be able to use it like this:
proc master_version_of_foo {ns args} {
namespace upvar $ns abc local1 def local2
# ... continue with your code in here
}
# Stamp out some copies
namespace eval ::x {}
interp alias {} ::x::foo {} ::master_version_of_foo ::x
namespace eval ::y {}
interp alias {} ::y::foo {} ::master_version_of_foo ::y
namespace eval ::z {}
interp alias {} ::z::foo {} ::master_version_of_foo ::z
These true command aliases are pretty fast, the variable binding is pretty fast too (similar in speed to the global command; they use virtually the same bytecode operations internally) and you'll be sharing the compilation of the procedure which is itself pretty fast.
The main reason for not doing this is if you need different command resolution in the three cases. At that point, the fastest routes all go through TclOO (which tames quite a few of the advanced capabilities of Tcl to the point of being usable) and probably require some serious redesign on your part to use well.
I have a little problem which I cannot explain at the moment. I created a minimalistic code snippet to show my problem or lack of understanding how tcl namespaces are working.
So I have the file test.tcl:
namespace eval test {
proc print {file_name} {
namespace inscope ::test2 {
printFileName $::test::file_name
}
}
}
namespace eval test2 {
proc printFileName {file_name} {
puts $file_name
}
}
Than I use tclsh and run:
source test.tcl
test::print test.dat
Which returns:
can't read "::test::file_name": no such variable
Why is that should the argument of test::print not be in the ::test namescope?
I have an easy workaround with set ::test::filename $filename before namespace inscope {}.
But I am not satisfied since I miss something here.
I cannot just run ::test2::printFileName $file_name since my real world code is more complex and does not run just one command it sources a list of commands which are all in a different namespace.
Local variables are not namespace variables. In particular, even with variable linking (the mechanism underlying upvar and global and variable etc.) formal parameter variables are never namespace variables in any way. That's just how the variables are mapped, because it's very fast to do; the procedure entry code is one of the hottest parts of Tcl's implementation code, so great efforts are taken to keep it as fast as possible.
But all is not lost!
You can copy the value to a namespace variable easily enough, or even do tricks with traces and upvar to make it appear like the local variable can be written back to from that interior scope. (You'll probably have to use info level to search back up the stack for where to inject the write, which will be horribly messy, but it will work.)
But what I'd instead do is make commands to provide the values (and possibly allow writing back as necessary). I think it's a bit cleaner.
namespace eval test {
proc print {file_name} {
proc ::test2::file_name {} [list return $file_name]
namespace eval ::test2 {
printFileName [file_name]
}
}
}
namespace eval test2 {
proc printFileName {file_name} {
puts $file_name
}
}
You can make this more elegant through the use of namespace path so that you don't have to build a whole new procedure each time you call. interp alias can help too (it's a good way to do argument currying, if you're familiar with that sort of thing from functional programming).
The problem here is that ::test::file_name refers to the file_name variable in the ::test namespace and not the local variable file_name as it seems that you want. That's just the way variable name resolution works. Local variables that are arguments to commands don't reside in the enclosing namespace.
Also, it is unusual to see namespace inscope invoked directly in a script. I would write this instead:
namespace eval test {
proc print {file_name} {
{*}[namespace eval ::test2 namespace code printFileName] $file_name
}
}
namespace eval test2 {
proc printFileName {file_name} {
puts $file_name
}
}
Or some variation if you don't have {*} in your version of Tcl.
But your last comment about not being able to run the command directly makes me suspect that this approach may not yet solve your problem.
Is there a way(a method call) to find out the name of the current package in tcl??
Eg:
package provides abc
proc A {
// I need to print the package name abc.
}
I know the class name here is obviously "abc" but still I want to print it out using a tcl command. I'm working on some debug modules and hence need this. (Similar to what perl provides: __PACKAGE__)
I am not aware of anything like that. However, you can work around:
set __PACKAGE__ foo
package provide $__PACKAGE__ 1.0
# Use can use the variable $__PACKAGE__ from now on
You are missing a few pieces of the puzzle. Even though you declared proc A in a file that is part of a package, A is still created globally.
The package command really just helps tcl figure out which file to source. You usually want to mix package provide with namespace
package provide abc
namespace eval ::abc {
proc A {} {puts stdout "I am in namespace [namespace current]"}
proc B {} {..}
proc C {} {..}
}
In order to call this function you would say
::abc::A
From inside the body of A you can tell what namespace you are in by using namespace current
An alternate way of writing this would be
namespace eval ::abc {}
proc ::abc::A {} {puts stdout "I am in namespace [namespace current]"}
proc ::abc::B {} {..}
proc ::abc::C {} {..}
There is not a one to one mapping between packages and namespaces. So one package could create many namespaces (or like in your example, no namespaces).
Check out this page for how to build libraries:
http://www.tcl.tk/man/tcl8.5/tutorial/Tcl31.html
And this page for full instructions on package and namespace
http://www.tcl.tk/man/tcl8.6/TclCmd/contents.htm
Can we rename constructors like we rename functions using the %rename directive?
%rename(create_cell) Cell(string);
Basically, I want to end up with something like create_cell instead of new_Cell.
I suspect that you can't at that point (did you try it to see if it works?) but there are a few things you can do. (Only do one of them, of course.)
Edit the generated code (SWIG writes the C++–Tcl binding code that is then compiled) so that the string "new_Cell" is "create_cell". I think you should be able to find the place to change in an argument a function call like Tcl_CreateCommand or Tcl_CreateObjCommand, but might also be in a macro depending on how the code generation is done. (I've never actually looked.)
Use load to get the code into Tcl and then rename the command afterwards. Names are not fixed in stone. The load might be inside the implementation of a call to package require; just do what you would normally do to get the code working with the wrong name first, and then do this:
rename new_Cell create_cell
Add a wrapper command or procedure; any of these will do:
proc create_cell args {
eval new_Cell $args
}
# With 8.5 or later
proc create_cell args {
new_Cell {*}$args
}
# With 8.6
proc create_cell args {
tailcall new_Cell {*}$args
}
# Or do this; not a procedure, an alias
interp alias {} create_cell {} new_Cell