- namespace code script
From the Tcl chatroom on 2004-11-03:dkf: You can probably hack something like autoexpansion with the help of namespace code
In [1
], DGP has this to say about the "crazy aunt":
specify fix parameters to callback command proc lambdaish args {uplevel 1 [list ::namespace code $args]}
% [lambdaish format %.3f] [expr {atan2(0,-1)}]
3.142suchenwi: Cool, Donal! It's not exactly lambdaish, as it doesn't take a parameter list... which is half a lambda. Why not just call it "curry"? % [curry format %.3f] [expr {atan2(0,-1)}]
3.142Somehow makes more sense to me...dkf: Pop that on the wiki. It also should work with any version of Tcl from 8.0 onwards. (though to 8.5; feature removed after that)jenglish: the 'namespace code' trick, alas, is not cool at all -- it relies on an undocumented, hairy, and almost-certainly-incorrect misfeature of unknown.dkf: It's an intended feature of unknown. It's a crazy aunt and not just a bug. There's too much code enforcing it in namespace.test for me to believe it to be anything other than intended. namespace code is just a constructor for namespace inscopeIn [1
], DGP has this to say about the "crazy aunt":- That code in unknown is a workaround for alleged brokenness in Itcl. No correctly written code should ever end up there.
- If you do end up there, your program is probably missing an {*} or an eval where one is needed. Correct that.
- The only fix I plan to ever make to that bit of code is its removal.
HaO 2008-09-02: When using namespace code to reference a namespace local function, one may use concat to add parameter values from the current scope. If the reference gets any parameters, they are added after this parameter:
by Don Porter:
namespace eval mynamespace {
namespace export getreference
proc callback {fix variable} {
puts "Called with: <$fix> <$variable>"
}
proc getreference {fix} {
return [concat [namespace code callback] [list $fix]]
}
}
namespace import mynamespace::*
set Ref [getreference "fix value"]
--> ::namespace inscope ::mynamespace callback {fix value}
eval $Ref {"variable value"}
--> Called with: <fix value> <variable value>
eval $Ref {"another value"}
--> Called with: <fix value> <another value>The same result may be acheved by using only list (only differences to the upper example shown). The first argument is now within the command list which works too:...
proc getreference {fix} {
return [namespace code [list callback $fix]]
}
...
set Ref [getreference "fix value"]
--> ::namespace inscope ::mynamespace {callback {fix value}}
...or the tcl 8.5 delist operator and list:...
proc getreference {fix} {
return [list {*}[namespace code callback] $fix]
}
...
set Ref [getreference "fix value"]
--> ::namespace inscope ::mynamespace callback {fix value}
...HaO 2012-12-17: The following errorneous way worked until tcl 8.6. Here is the tcl8.6 error message:...
proc getreference {fix} {
return [list [namespace code callback] $fix]
}
...
set Ref [getreference "fix value"]
--> {::namespace inscope ::mynamespace callback} {fix value}
...
after 10 "$Ref 1"
--> bgerror: invalid command name "::namespace inscope ::mynamespace callback"Here is the explanation on clt
by Don Porter:Crazy Aunt Millie is dead.
In 8.5, your broken code works because ages ago, a workaround was
actually put into Tcl's default [unknown] command to forgive broken
code, and attempt to "Do What They Mean". It's been murky for a long
time just who we were helping with this. Legends claimed Itcl needed
it, but the evidence was pretty weak. Taking it out did not break Itcl.
In 8.6 we stopped doing that. We expect programmers to code what they
mean. That means putting {*} where they go. Or, if you just really
like what you had -- or have too much code to correct -- then put
the forgiving [unknown] back yourself, or even just in your namespace
with [namespace unknown]. 