El martes, 12 de abril de 2022 a las 13:18:32 UTC+2, Andreas Leitgeb escribió:
Tcl just doesn't offer that specific mechanics:
"for reading variables, fall back to outer scope(s) until such a var is found."
You could mimic such mechanic, if you knew the variables in advance, and
set read-traces for the variables, and within the traces look up the var
in the outer scopes, but that may also not help here
Whatever solution can be offered, they'd all have their downsides.
Choose what downsides are least unacceptible for you and see if you can
live with them:
-) manually copying all variables from all outer scopes into current scope. downside: performance, maybe also clash between variables and arrays
yes, and maybe clash with dicts also or any other variable type could appear in future tcl versions. Performance is the main con here, that's why I said my own solution doesn't satisfy me ;-) Another con is scalability
-) creating read-traces for a list of variables that you might want to
read from within "let*".
may you further expound this?
-) let the let*-bodies run in caller scope (read access to all vars in
that scope) but deal with variables that may be oberwritten to restore
them afterwards.
I think this will be hard to achieve and also offer poor performance, I should parse all body to see what commands modify variables in any way, even as a colateral effect.
pick your poison ;-)
yeah, every choice is a poison ;-)
I think one problem is the way tcl procs treat variables, from a tcl proc point of view there's only current level variables (local) or toplevel variables (global) but nothing in between, for all the rest you should explicitly use uplevel to explore the stack frame, because there's no closure in tcl procs.
Actually: from a tcl proc point of view there's only current level
variables - full stop.
that's true.
Additional to that, variables can be linked in from outside, where "outside" may be global, any namespace, or even upper caller-frames. Each of
these variables can be linked into current scope to a local name,
using "global", "variable", or "upvar" commands to establish the links.
yes, ok. What I tried to mean is you have two "declarative" ways to refer a variable: current level as local or toplevel as global. While refering any other variable in the frame stack is "procedimental" in a sense it depends on you current position in
the stack frame.
But once, the link is created, any write to such a variable will also
go to the original variable from other scope - thus it won't help
you with your apparent goal of separating read and write access.
Yes, I know but maybe I don't fully understand the implications
In my understanding (possibly erroneous) namespaces is all about scope not stack frames, from a scope point of view there're only namespaces: global namespace, "local" namespace, whatever namespace you create (eval)...
From the execution point of view there're only stack frames, and you can have variables in current stack frame (level) binded to variables defined in several scopes using the appropiate commad (local, global, upvar, variable...)
It happens toplevel define all variables in global namespace but from the point of view of level 0 you could say all variables in global namespace are local in the sense they are defined in the current level (toplevel), with "define" I mean set command
always creates the variable in the current level, in the current stack frame.
So it doesn't matter which scope the variable is defined, once you create it in a stack frame (by global, local, variable...) it is directly accesible in that stack frame becouse exists in that stack frame (binded to the right variable)
So the question is when a new stack frame is created? my answer is everytime you execute a proc
ok but what is executing a proc? obviously is executing a defined proc, but also executing a lambda (apply) and maybe other executions...
for example, namespace eval creates a new stack frame? The doc is not clear and I'm not convinced based on code testing:
% namespace eval XXX { proc l {} {info level} }
% XXX::l
1
% namespace eval XXX { proc nl {} {namespace eval Y {info level}} }
% XXX::nl
2
% namespace eval XXX { namespace eval Y {info level} }
2
From first command I understand namespace eval does not create a new stack frame, it's the proc call what creates it.
From second command I understand namespace eval creates a new stack frame and that's the reason for level 2 rather than 1 as it should be since I execute only one proc
Third commands seems to support the last conclusion, two namespace eval returns a level 2, rather than level 0
I'm a bit confused.
regards
--- SoupGate-Win32 v1.05
* Origin: fsxNet Usenet Gateway (21:1/5)