- namespace current
Jasp: The so called convenience of returning :: has actually become an annoyance for me. The following code is supposted to take the argument variable database, containing a procedure name, and get its full path (prepend command works like append, except inserts the concentration of arguments at start of variable):
if {[string range $database 0 1] ne {::}} { ::emerald::data::prepend database [uplevel 1 {namespace current}] ::}This code works fine all the time, except when namespace current returns ::. $database then becomes something like ::::procedure instead of ::procedure. I'm going to do a check with if and not prepend :: for this result for now, can anyone recommend a better solution? I think namespace current needs an argument like -actual to prevent this behaviour.RS: Except for ugly looks, :::: will not hurt your program execution, as "two or more colons" are parsed as namespace separator.schlenk: You may even use the wrong tool for the job, namespace which could be more like what you want.Jasp: Ah!, why did I miss namespace which while reading the manual?, knowing of it will help. Currently in the procedure of this code, the procedure specified in database may not yet exist, but only when using certain "subcommands". However with your notes in mind, I should be able to modify it to work correctly without current hack. Thanks. :)NEM: For names that don't yet exist, I use these little utility procs:
proc nsjoin {ns name} { if {![string match ::* $name]} { set name [string trimright $ns :]::$name } return $name } proc resolve name { nsjoin [uplevel 1 { namespace current }] $name }(I also don't like names like ::::foo - two colons is ugly enough).Jasp: The problem with nsjoin there, is that it only removes one bit of excessive colons. The procedure I'm working on keeps a database of infomation for the procedures it works with (which are sort of like objects, but not exactly), and if a procedure is specified as both foo::bar and foo::::bar without being normalized in a way, then it could keep two separate records for the same procedure, not the wanted behaviour. - RS A simple fix would be, called after composing namespaced names,
regsub -all :::+ $name :: nameJasp: I was thinking something like that.NEM: Right. If you used nsjoin to build all your namespace paths then you wouldn't have this problem, of course. - Jasp Yes, but my project is a framework for other packages to use, and I can't count on the other developers using something like nsjoin also.MG: One thing I find very curious looking at the discussion above, and RS's regsub solution:
% proc :foo {string} { % puts ":foo $string" % } % :foo bar :foo bar % namespace current :: % namespace which :foo :::foo % :::foo bar invalid command name ":::foo"There could be something I'm missing - I don't work with namespaces often in Tcl, and aren't greatly familiar with their working - but I can't seem to find a good way to specify the full namespace for a command called ':foo', with the exception of:
% namespace eval :: {:foo bar} :foo barwhich I believe (?) works slightly differently.schlenk: There are some problems when using namespaces and procs or variables starting with :, the best advice is avoid naming procs or vars like that.NEM: Because of this difficulty, Tcl will stop you creating a command starting with a : in any but the global namespace:
% namespace eval bar { proc :foo {} {} } can't create procedure ":foo" in non-global namespace with name starting with ":"I guess it allows it in the global namespace for backwards compatibility with pre-namespace Tcl scripts. One upshot of this is that ":foo" always refers to a command in the global namespace, so it is fully-qualified without needing the :: prefix.MG: Ahh, that wasn't something I'd even thought to try, and does make things much easier (if you're silly enough to use :something for a command name). Thanks, NEM!