Rocksolid Light

Welcome to Rocksolid Light

mail  files  register  newsreader  groups  login

Message-ID:  

"Nuclear war would really set back cable." -- Ted Turner


devel / comp.lang.tcl / Re: Smuggling variables into namespaces

SubjectAuthor
* Smuggling variables into namespacesLuc
`* Re: Smuggling variables into namespacesRich
 `* Re: Smuggling variables into namespacesLuc
  `- Re: Smuggling variables into namespacesRich

1
Smuggling variables into namespaces

<20240127000027.5a0c2297@lud1.home>

  copy mid

https://news.novabbs.org/devel/article-flat.php?id=13243&group=comp.lang.tcl#13243

  copy link   Newsgroups: comp.lang.tcl
Path: i2pn2.org!i2pn.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: luc@sep.invalid (Luc)
Newsgroups: comp.lang.tcl
Subject: Smuggling variables into namespaces
Date: Sat, 27 Jan 2024 00:00:27 -0300
Organization: A noiseless patient Spider
Lines: 43
Message-ID: <20240127000027.5a0c2297@lud1.home>
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: dont-email.me; posting-host="99524dcbe89d9e140058aa94e1ebb786";
logging-data="3289238"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18N7YlQkQKj5qOJP1p18lkkitT5Drsl7PU="
Cancel-Lock: sha1:ktGPIJc1vWQUDpnlEoHoBuAIhpI=
 by: Luc - Sat, 27 Jan 2024 03:00 UTC

Like I said some time ago, I am enjoying using namespaces because I
create them then eval stuff inside them and everything works fine.

There is only one thing that is bugging me:

proc SomeProc {arg1 arg2} {
namespace eval MYNS {
if {$arg1 > $arg2} {puts "1 is greater than 2!"}
}
}

Of course it doesn't work. This works:

proc SomeProc {arg1 arg2} {
set MYNS::arg1 $arg1
set MYNS::arg2 $arg2

namespace eval MYNS {
if {$arg1 > $arg2} {puts "1 is greater than 2!"}
}
}

Since I use a lot of procs and namespaces in my code, I find myself
doing it a lot. It works, but it's only clunky, I often feel somehow like I
am doing something that I am not really supposed to. It's kludgy.

Is there a smarter way of handling that?

Notes:

1. In the second code snippet, the MYNS namespace has been created
earlier in the code.

2. I can't create MYNS::SomeProc because in many cases the namespace
is created and destroyed on the fly so its name is unpredictable.

--
Luc
>>

Re: Smuggling variables into namespaces

<up242v$3909a$1@dont-email.me>

  copy mid

https://news.novabbs.org/devel/article-flat.php?id=13244&group=comp.lang.tcl#13244

  copy link   Newsgroups: comp.lang.tcl
Path: i2pn2.org!i2pn.org!news.niel.me!news.gegeweb.eu!gegeweb.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: rich@example.invalid (Rich)
Newsgroups: comp.lang.tcl
Subject: Re: Smuggling variables into namespaces
Date: Sat, 27 Jan 2024 05:24:47 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 103
Message-ID: <up242v$3909a$1@dont-email.me>
References: <20240127000027.5a0c2297@lud1.home>
Injection-Date: Sat, 27 Jan 2024 05:24:47 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="af3176d436ddb0be9a0d952d73411b55";
logging-data="3440938"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18B0xxEpNIKOvtlokFOWo1Z"
User-Agent: tin/2.6.1-20211226 ("Convalmore") (Linux/5.15.139 (x86_64))
Cancel-Lock: sha1:7Enpbq+OA3yrjNJacEBZMy+Ah6k=
 by: Rich - Sat, 27 Jan 2024 05:24 UTC

Luc <luc@sep.invalid> wrote:
> Like I said some time ago, I am enjoying using namespaces because I
> create them then eval stuff inside them and everything works fine.
>
> There is only one thing that is bugging me:
>
> proc SomeProc {arg1 arg2} {
> namespace eval MYNS {
> if {$arg1 > $arg2} {puts "1 is greater than 2!"}
> }
> }
>
>
> Of course it doesn't work.

Assuming that the MYNS namespace above did not secretly have arg1
and arg2 variables created elsewhere, this fails because of the
namespace name resolution rules. Your 'if' is running "in a namespace
eval", so it first looks in the current namespace (MYNS), finds no arg1
in MYNS, and then looks in the global namespace (and assuming there is
no global "arg1", it finds no variable named "arg1" anywhere.

Because of the namespace rules, the if simply can not see the arg1/arg2
of the proc inside which it (the eval) is running.

> This works:
> proc SomeProc {arg1 arg2} {
> set MYNS::arg1 $arg1
> set MYNS::arg2 $arg2
>
> namespace eval MYNS {
> if {$arg1 > $arg2} {puts "1 is greater than 2!"}
> }
> }

Assuming "SomeProc" is as above, and is not itself inside another,
unstated, namespace, this works because the two sets create arg1 and
arg2 variables in the MYNS namespace. So when the namespace eval happens
there are at least two variables existing in the namespace. So the if,
when it follows the rule of "look in current namespace" (MYNS) it finds
both an arg1 and arg2 and runs without giving a 'variable not found'
error.

> Since I use a lot of procs and namespaces in my code, I find myself
> doing it a lot. It works, but it's only clunky, I often feel somehow like I
> am doing something that I am not really supposed to. It's kludgy.
>
> Is there a smarter way of handling that?

Depends on just what 'that' is which you are referring. One thing that
your last few posts has indicated is that you seem to be running code
directly in the namespace eval script. While that does work, it really
is not the intent of namespaces.

The basic intent is for them to look like this:

namespace eval NS {
variable var1 [init var1]
variable var2

proc abc {a1} {
variable var1
#do something with a1 and var1
}

proc def {b1} {
variable var2
#do something with b1 and var2
}
}

And then you call NS::abc and NS::def as needed to "do something".

So really answering the 'is there a smarter' question requires you
describe what you are really trying to do or are trying to squeeze
namespaces into doing for you.

> Notes:
>
> 1. In the second code snippet, the MYNS namespace has been created
> earlier in the code.
>
> 2. I can't create MYNS::SomeProc because in many cases the namespace
> is created and destroyed on the fly so its name is unpredictable.

Sure you can. In order to create MYNS on the fly, you have to create
'something' as its name, so you can create 'SomeProc' inside of it, and
call it using the created name just fine.

$ rlwrap tclsh
% set nsname [expr {rand()}]
0.6244215865733203
% proc abc {nsname} {
namespace eval $nsname {
proc SomeProc {arg1} {
puts "Hi from SomeProc, my arg1='$arg1'"
}
}
}
% abc $nsname
% ${nsname}::SomeProc Hello
Hi from SomeProc, my arg1='Hello'

Re: Smuggling variables into namespaces

<20240127150820.369cc7a9@lud1.home>

  copy mid

https://news.novabbs.org/devel/article-flat.php?id=13250&group=comp.lang.tcl#13250

  copy link   Newsgroups: comp.lang.tcl
Path: i2pn2.org!i2pn.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: luc@sep.invalid (Luc)
Newsgroups: comp.lang.tcl
Subject: Re: Smuggling variables into namespaces
Date: Sat, 27 Jan 2024 15:08:20 -0300
Organization: A noiseless patient Spider
Lines: 103
Message-ID: <20240127150820.369cc7a9@lud1.home>
References: <20240127000027.5a0c2297@lud1.home>
<up242v$3909a$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=US-ASCII
Content-Transfer-Encoding: 7bit
Injection-Info: dont-email.me; posting-host="99524dcbe89d9e140058aa94e1ebb786";
logging-data="3652185"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/4qjmTzuLpyoyGXq6Sl8enOhdAulhRtVc="
Cancel-Lock: sha1:OKs3JJy4S0IxicyTo/64raZ+qU8=
 by: Luc - Sat, 27 Jan 2024 18:08 UTC

On Sat, 27 Jan 2024 05:24:47 -0000 (UTC), Rich wrote:

>Depends on just what 'that' is which you are referring. One thing that
>your last few posts has indicated is that you seem to be running code
>directly in the namespace eval script.

By 'that' I mean having the code inside a namespace use data that has
been created outside of it. The way I'm doing it is exactly like using
::tsv with threads. But threads have completely separate interpreters.
Namespaces don't.

>While that does work, it really is not the intent of namespaces.

So maybe you're just telling me that what I'm doing is unusual at
heart and the way I'm doing it is the only unusual way of carrying on
my unusual approach.

>The basic intent is for them to look like this:
>
>namespace eval NS {
> variable var1 [init var1]
> variable var2
>
> proc abc {a1} {
> variable var1
> #do something with a1 and var1
> }
>
> proc def {b1} {
> variable var2
> #do something with b1 and var2
> }
>}

You put procs inside namespaces. That's what every example out there
does. I have the opposite, I'm dealing with namespaces inside procs.
Different laws of physics.

>> 2. I can't create MYNS::SomeProc because in many cases the namespace
>> is created and destroyed on the fly so its name is unpredictable.
>
>Sure you can. In order to create MYNS on the fly, you have to create
>'something' as its name, so you can create 'SomeProc' inside of it, and
>call it using the created name just fine.
>
> $ rlwrap tclsh
> % set nsname [expr {rand()}]
> 0.6244215865733203
> % proc abc {nsname} {
> namespace eval $nsname {
> proc SomeProc {arg1} {
> puts "Hi from SomeProc, my arg1='$arg1'"
> }
> }
> }
> % abc $nsname
> % ${nsname}::SomeProc Hello
> Hi from SomeProc, my arg1='Hello'

That works in theory but not in practice. Every "tab" has its own
namespace whose name is generated on the fly (clock milliseconds).
Every new tab has to go through a certain... procedure. A Tcl proc,
naturally. I have to prescribe that procedure. I can't create and
name that proc inside a namespace that doesn't exist yet. I think
it's very obvious that I should prescribe one single global proc
and execute it inside the countless namespaces that will be born
and die at runtime.

Unless I rename that proc.

proc SomeProc {} {
do whatever
}

set id [clock milliseconds]
namespace eval $id {}
rename SomeProc id::SomeProc
namespace eval $id {
SomeProc
}

But that is not what your example suggests and I am not very confident
that renaming that crucial proc every time a tab is created will be
a good idea.

If only I could clone that proc... Damn, you were right. I am doing
OOP!

OK, it's an idea. I can clone procs. I ran a search and found something
interesting about that. I will investigate it.

Thank you.

--
Luc
>>

Re: Smuggling variables into namespaces

<up3o4e$3h4mi$1@dont-email.me>

  copy mid

https://news.novabbs.org/devel/article-flat.php?id=13251&group=comp.lang.tcl#13251

  copy link   Newsgroups: comp.lang.tcl
Path: i2pn2.org!i2pn.org!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: rich@example.invalid (Rich)
Newsgroups: comp.lang.tcl
Subject: Re: Smuggling variables into namespaces
Date: Sat, 27 Jan 2024 20:13:02 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 209
Message-ID: <up3o4e$3h4mi$1@dont-email.me>
References: <20240127000027.5a0c2297@lud1.home> <up242v$3909a$1@dont-email.me> <20240127150820.369cc7a9@lud1.home>
Injection-Date: Sat, 27 Jan 2024 20:13:02 -0000 (UTC)
Injection-Info: dont-email.me; posting-host="af3176d436ddb0be9a0d952d73411b55";
logging-data="3707602"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18l8cHC+uEpteRLk1c+IogA"
User-Agent: tin/2.6.1-20211226 ("Convalmore") (Linux/5.15.139 (x86_64))
Cancel-Lock: sha1:cRtyp0f8XG3kHb3VJcC2J3t7/v0=
 by: Rich - Sat, 27 Jan 2024 20:13 UTC

Luc <luc@sep.invalid> wrote:
> On Sat, 27 Jan 2024 05:24:47 -0000 (UTC), Rich wrote:
>
>>Depends on just what 'that' is which you are referring. One thing that
>>your last few posts has indicated is that you seem to be running code
>>directly in the namespace eval script.
>
> By 'that' I mean having the code inside a namespace use data that has
> been created outside of it. The way I'm doing it is exactly like using
> ::tsv with threads. But threads have completely separate interpreters.
> Namespaces don't.

The "usual" way for "code inside a namespace" (which conventionally
means procs in the namespace, not just "bare script") is for that
outside data to be passed in as arguments to the procs that live in the
namespace.

Namespaces are a container for a set of procs (usually 'related' procs,
but that's just a convienent organizational aspect) and for
"semi-global" data used by those procs. By "semi-global" I mean the
"namespace variables" that are created by "variable xyz" in the eval
script, or by explicit paths (::abc::def::var). They exist like
'globals' do, to the extent that the procs in the namespace have them
live beyond the time during which each proc is called. But they are
only "semi-global" because they are not out in the single, main,
interpreter wide, global namespace. So two namespaces can each have a
"history" variable, and that "history" var is independent in both, and
does not overlap with a real "global" "history" var as well.

>>While that does work, it really is not the intent of namespaces.
>
> So maybe you're just telling me that what I'm doing is unusual at
> heart and the way I'm doing it is the only unusual way of carrying on
> my unusual approach.

So far the code snippets you've been posting all imply that all you do
with namespaces is run bare code inside of them. If that is all you
are doing, then yes, your usage is 'unusual'. It's not 'wrong' in that
it works, but it is 'unusual' because you lose much of the value of
namespaces in the process.

>>The basic intent is for them to look like this:
>>
>>namespace eval NS {
>> variable var1 [init var1]
>> variable var2
>>
>> proc abc {a1} {
>> variable var1
>> #do something with a1 and var1
>> }
>>
>> proc def {b1} {
>> variable var2
>> #do something with b1 and var2
>> }
>>}
>
> You put procs inside namespaces. That's what every example out there
> does. I have the opposite, I'm dealing with namespaces inside procs.
> Different laws of physics.

Except you don't have "namespaces inside procs". Namespaces live
outside of procs and the proc variable call stack. All you are doing
is "creating namespaces inside procs" -- but they don't actually
'exist' inside the procs. Which is likely where you keep running into
these impedance mismatches between what you want to do, and how
namespaces actually work.

>>> 2. I can't create MYNS::SomeProc because in many cases the
>>> namespace is created and destroyed on the fly so its name is
>>> unpredictable.
>>
>>Sure you can. In order to create MYNS on the fly, you have to create
>>'something' as its name, so you can create 'SomeProc' inside of it,
>>and call it using the created name just fine.
>>
>> $ rlwrap tclsh
>> % set nsname [expr {rand()}]
>> 0.6244215865733203
>> % proc abc {nsname} {
>> namespace eval $nsname {
>> proc SomeProc {arg1} {
>> puts "Hi from SomeProc, my arg1='$arg1'"
>> }
>> }
>> }
>> % abc $nsname
>> % ${nsname}::SomeProc Hello
>> Hi from SomeProc, my arg1='Hello'
>
> That works in theory but not in practice. Every "tab" has its own
> namespace whose name is generated on the fly (clock milliseconds).

Using clock milliseconds is litte different from my 'rand()' call
above. An arbitrary "name" gets created.

> Every new tab has to go through a certain... procedure. A Tcl proc,
> naturally.

Given that tabs don't "go through procs" I presume you meant: "every
new tab needs to have a certian amount of 'initialization' performed
upon it". And implying that you are performing that initialization by
calling a proc that does the work. In which case, you can still use an
otherwise before unknown name for the namespace (clock miliseconds or
rand()) and do all the init via the 'init a tab' proc.

> I have to prescribe that procedure. I can't create and
> name that proc inside a namespace that doesn't exist yet.

The proc that creates the namespace, and sets it up, does not have to
reside "in" that namespace in order to do the init.

I.e.:

#!/usr/bin/wish

# true global to provide separate toplevel names
set seq 0

proc init-tab {} {

set ns [clock milliseconds]

# create the namespace
namespace eval $ns {
variable data 0
variable seq 0

proc callback {tl} {
variable data
variable seq
tk_dialog .dialog[incr seq] "Hi There" \
"proc 'callback' in namespace '[namespace current]' was called. data='$data'" \
"" 0 "Dismiss"
incr data
}

proc init-gui {seq} {
# this example simply uses plural toplevels to 'simulate' plural tabs
set tl [toplevel .[incr seq]]
button $tl.b -text "Click Me" -command [namespace code [list callback $tl]]
pack $tl.b
}
}

# set data within the namespace to something besides zero:
set ${ns}::data [expr {42 + int(rand()*42)}]

# trigger GUI initialization:
${ns}::init-gui [incr ::seq]
}

init-tab

init-tab

> I think it's very obvious that I should prescribe one single global
> proc and execute it inside the countless namespaces that will be born
> and die at runtime.
>
> Unless I rename that proc.
>
> proc SomeProc {} {
> do whatever
> }
>
> set id [clock milliseconds]
> namespace eval $id {}
> rename SomeProc id::SomeProc
> namespace eval $id {
> SomeProc
> }
>
> But that is not what your example suggests and I am not very confident
> that renaming that crucial proc every time a tab is created will be
> a good idea.

That would only work if you remember where you 'renamed' it in order to
move it back out to another new namespace. 'rename' does not create a
copy, it moves the proc to that new name. And to make it work, you
need to make the rename be "rename SomeProc ${id}::SomeProc".

> If only I could clone that proc... Damn, you were right. I am doing
> OOP!

Yes, you are creating a custom 'object system'. In which case, unless
you want your own custome 'object system' you might consider using one
of the existing object systems (tcloo or SNIT are two possibilities).

You may want to give a read through the OO chapter of Ashok's book,
available online here: https://www.magicsplat.com/articles/oo.html.
You may find that actually using tcloo may be easier than trying to
push "namespace" to do what you want. I.e., Tcloo objects include a
built in 'initializer' method that you define that then automatically
does the "init" work when a new object is created. As well, you can
let Tcloo assign 'names' to objects for you, so you don't need to worry
about 'clock microseconds'. You just 'create' another object, and it
gets an automatic name assigned.

> OK, it's an idea. I can clone procs. I ran a search and found something
> interesting about that. I will investigate it.

Yes, but see above, it is not necessary for a proc that creates and
sets up a namespace to exist within that namespace. Requiring that
would create very much of a "which came first, the chicken or the egg"
problem.

1
server_pubkey.txt

rocksolid light 0.9.8
clearnet tor