| View previous topic :: View next topic |
| Author |
Message |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sat Apr 04, 2009 3:11 pm Post subject: Create variable name on the fly |
|
|
Hello,
Is there a way to create a variable or array name, based on the nick of the user that called the proc that is using the variable or array?
Naming the new var nick-temp would be ok, as I intend to unset it at the end of the proc.
I must be overlooking something....
Thanks |
|
| Back to top |
|
 |
arfer Master

Joined: 26 Nov 2004 Posts: 436 Location: Manchester, UK
|
Posted: Sat Apr 04, 2009 6:27 pm Post subject: |
|
|
You can create a variable with name equal to the value of another variable.
Say for example I set the value of the variable named testnick ($testnick) to arfer, then use it to create a variable named arfer (with value "my nick").
[23:23] <arfer> .tcl set testnick arfer
[23:23] <osmosis> Tcl: arfer
[23:24] <arfer> .tcl set $testnick "my nick"
[23:24] <osmosis> Tcl: my nick
[23:24] <arfer> .tcl set arfer
[23:24] <osmosis> Tcl: my nick
A new variable was created called arfer, with a value "my nick" as evidenced by the final set command above. _________________ I must have had nothing to do |
|
| Back to top |
|
 |
speechles Revered One

Joined: 26 Aug 2006 Posts: 1398 Location: emerald triangle, california (coastal redwoods)
|
Posted: Sat Apr 04, 2009 9:24 pm Post subject: |
|
|
| Quote: | *** n is set to "jim"
<speechles> .set n "jim"
<sp33chy> Ok, set.
*** nick_jim is set to "beam"
<speechles> .set nick_$n "beam"
<sp33chy> Ok, set.
*** show the contents of new variable nick_jim
<speechles> .tcl set nick_jim
<sp33chy> Tcl: beam |
setting an array, just use set arrayname($nick) "something" _________________ speechles' eggdrop tcl archive |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 05, 2009 4:33 pm Post subject: |
|
|
| speechles wrote: | | Quote: | *** n is set to "jim"
<speechles> .set n "jim"
<sp33chy> Ok, set.
*** nick_jim is set to "beam"
<speechles> .set nick_$n "beam"
<sp33chy> Ok, set.
*** show the contents of new variable nick_jim
<speechles> .tcl set nick_jim
<sp33chy> Tcl: beam |
|
Thanks for replying.
I'm not there yet.
Based on your above, and that I want to create the variable based on the nick of the user calling it, I tried this:
| Code: |
bind pub - !test atest_proc
proc atest_proc {nick uhost handle chan text} {
set nick_$nick "beam"
putserv "privmsg $chan : nick_$nick is set to $nick_$nick "
}
|
with great suspicion about what might happen with the last line.
But I didn't even get that far.
When I caused the proc to run, I get this in partyline:
| Quote: |
Tcl error [atest_proc]: can't read "nick_": no such variable
|
Next, just to be sure of typos, etc. , I tried this:
| Code: |
proc atest_proc {nick uhost handle chan text} {
set n "jim"
set nick_$n "beam"
putserv "privmsg $chan : var named nick_$n is set to $nick_$n "
}
|
and still get
| Quote: |
Tcl error [atest_proc]: can't read "nick_": no such variable
|
Isn't that strange?... that it works from the command line, but not in a procedure?
What do you think?
| Quote: |
setting an array, just use set arrayname($nick) "something"
|
Wouldn't that just set an element within the array though?
I need the array name to be based on the nick somehow.
Thanks |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 05, 2009 4:53 pm Post subject: |
|
|
| arfer wrote: | You can create a variable with name equal to the value of another variable.
Say for example I set the value of the variable named testnick ($testnick) to arfer, then use it to create a variable named arfer (with value "my nick").
[23:23] <arfer> .tcl set testnick arfer
[23:23] <osmosis> Tcl: arfer
[23:24] <arfer> .tcl set $testnick "my nick"
[23:24] <osmosis> Tcl: my nick
[23:24] <arfer> .tcl set arfer
[23:24] <osmosis> Tcl: my nick
A new variable was created called arfer, with a value "my nick" as evidenced by the final set command above. |
Not ignoring your post.
Thank you very much for replying too.
I'm still experimenting with this. I think I have a mental block or something as it is easy to lose my place when doing this.
Will let you know if I get it |
|
| Back to top |
|
 |
arfer Master

Joined: 26 Nov 2004 Posts: 436 Location: Manchester, UK
|
Posted: Sun Apr 05, 2009 4:55 pm Post subject: |
|
|
It is the putserv statement that is causing the error, there is nothing wrong with the statement
set nick_$nick "beam"
Apart from it being rather horrendous code
Specifically, it is $nick_$nick that cannot be read. It is not even possible to enclose the name in braces ${nick_$nick} since this prevents the second $ from causing variable substitution.
I'm not sure if there is a solution to your specific method. I would urge you to reconsider what you are doing and why you are doing it. It is rather like having a variable name containing spaces, in that it generally leads to unnecessary difficulties somewhere down the line.
| Code: |
proc atest_proc {nick uhost handle chan text} {
set $nick "beam"
putserv "privmsg $chan :a variable named $nick has been created with value [subst $$nick]"
}
|
That code above ought to work but it's very messy. I am beginning to regret answering the original question because this is not something I would do. _________________ I must have had nothing to do |
|
| Back to top |
|
 |
arfer Master

Joined: 26 Nov 2004 Posts: 436 Location: Manchester, UK
|
Posted: Sun Apr 05, 2009 5:28 pm Post subject: |
|
|
Just to continue with the thread, the 'normal' way of creating a variable dynamically that is dependent on the value of another variable is to use arrays
So within the proc above
| Code: |
set ar($nick) "beam"
|
Much safer. The array named 'ar' now contains an element who's name is equal to the value of the variable named nick (ie. $nick), and this array element has a value "beam". It can be referrenced within the proc using $ar($nick).
Arrays also lend themselves to some very useful additional Tcl functions.
For example, if I knew an array element name contained the sequence of characters ARF but didn't know the exact nick it represented (element name) was arfer or the case was lower, I could find it using something like
| Code: |
set name [array names ar -regexp (?i)ARF]
|
Declare the array as global within the proc if you wish to use it elsewhere. _________________ I must have had nothing to do |
|
| Back to top |
|
 |
nml375 Revered One
Joined: 04 Aug 2006 Posts: 2857
|
Posted: Sun Apr 05, 2009 6:44 pm Post subject: |
|
|
Just to clarify one thing, that has not been covered in the previous posts...
You are currently dealing with variables in local namespaces (within the procs). These do not persist inbetween invocations of the proc. What you need to do, is to store the data in a variable in a global namespace. There are a few ways of doing this, such as using the global command, or full namespace paths.
I'll give you a few examples, which also shows how to handle the issue described by arfer a few posts up...
| Code: |
bind pub - !test atest_proc
####### Use global command to link the localspace variable to the globalspace one...
proc atest_proc {nick uhost handle chan text} {
global "nick_$nick"
set nick_$nick "beam"
putserv "privmsg $chan :nick_$nick is set to [set nick_$nick]"
}
####### Use full namespace path
proc atest_proc {nick uhost handle chan text} {
set ::nick_$nick "beam"
putserv "privmsg $chan :nick_$nick is set to [set ::nick_$nick]"
}
####### Use the upvar command to link the globalspace variable to "thenick"
proc atest_proc {nick uhost handle chan text} {
upvar #0 nick_$nick thenick
set thenick "beam"
putserv "privmsg $chan :nick_$nick is set to $thenick"
}
####### Use full namespace path along with arrays
proc atest_proc {nick uhost handle chan text} {
set ::nick_($nick) "beam"
puserv "privmsg $chan :nick_($nick) is set to $nick_($nick)"
}
|
_________________ NML_375, idling at #eggdrop@IrcNET |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 05, 2009 6:51 pm Post subject: |
|
|
| arfer wrote: | It is the putserv statement that is causing the error, there is nothing wrong with the statement
set nick_$nick "beam"
|
Ah! so it WAS the last line that I suspected. Didn't realize the proc was running that far.
| Quote: |
Apart from it being rather horrendous code
|
It even looked odd to me. But I was just trying to make minimal changes and trying to watch results, at this point.
| Quote: |
Specifically, it is $nick_$nick that cannot be read. It is not even possible to enclose the name in braces ${nick_$nick} since this prevents the second $ from causing variable substitution.
I'm not sure if there is a solution to your specific method. I would urge you to reconsider what you are doing and why you are doing it. It is rather like having a variable name containing spaces, in that it generally leads to unnecessary difficulties somewhere down the line.
|
I'm getting the feeling that I might be going about trying to accomplish the chore with the wrong ideas right from the start.
I've sent you a pm, that hopefully explains it. I hope you don't mind - just didn't want to drag more ugly code out - yet.
| Quote: |
| Code: |
proc atest_proc {nick uhost handle chan text} {
set $nick "beam"
putserv "privmsg $chan :a variable named $nick has been created with value [subst $$nick]"
}
|
That code above ought to work but it's very messy. I am beginning to regret answering the original question because this is not something I would do. |
This is new to me - the subst command. I've just been to the TCL online manual and looked it up, and I really don't 'get it' yet.
I text searched for $$ to and it was not on the page - I was hoping to find an example explaining the way you used it. It was not there.
This has become a side note now - you've made me curious about it. If there is a better way to get my job done, hopefully you'll be able to point me towards it after reading that explanation.
Thanks |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 05, 2009 6:54 pm Post subject: |
|
|
| arfer wrote: | Just to continue with the thread, the 'normal' way of creating a variable dynamically that is dependent on the value of another variable is to use arrays
So within the proc above
| Code: |
set ar($nick) "beam"
|
Much safer. The array named 'ar' now contains an element who's name is equal to the value of the variable named nick (ie. $nick), and this array element has a value "beam". It can be referrenced within the proc using $ar($nick).
Arrays also lend themselves to some very useful additional Tcl functions.
For example, if I knew an array element name contained the sequence of characters ARF but didn't know the exact nick it represented (element name) was arfer or the case was lower, I could find it using something like
| Code: |
set name [array names ar -regexp (?i)ARF]
|
Declare the array as global within the proc if you wish to use it elsewhere. |
I'd seen this somewhere, already. It won't work, for what I need... I need it the other way around - array name corresponding to nick. Already have all the elements. |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 05, 2009 6:58 pm Post subject: |
|
|
| nml375 wrote: | Just to clarify one thing, that has not been covered in the previous posts...
You are currently dealing with variables in local namespaces (within the procs). These do not persist inbetween invocations of the proc. What you need to do, ....
|
Why?
I don't need the variable outside the proc. Above, I'd said, "...as I intend to unset it at the end of the proc. " and now on second thought, that might not even be necessary. I hadn't thought of that.
And thank you for taking time to try to help. |
|
| Back to top |
|
 |
nml375 Revered One
Joined: 04 Aug 2006 Posts: 2857
|
Posted: Sun Apr 05, 2009 7:15 pm Post subject: |
|
|
willy,
Sorry, mis-read that line. No need for namespaces then.
The "[set nick_$nick]" approach of reading the variable should help you avoid the error of "can't read nick_: no such variable".
It might be possible to use the upvar trick with 0 level instead of #0, but I have not verified that. _________________ NML_375, idling at #eggdrop@IrcNET |
|
| Back to top |
|
 |
arfer Master

Joined: 26 Nov 2004 Posts: 436 Location: Manchester, UK
|
Posted: Sun Apr 05, 2009 7:22 pm Post subject: |
|
|
Subst is a command that is used to force variable, command or backslash substitution where it might otherwise fail to occur.
Take the following example :-
[00:15] <arfer> .tcl set a one
[00:15] <Baal> Tcl: one
[00:16] <arfer> .tcl set $a two
[00:16] <Baal> Tcl: two
[00:17] <arfer> .tcl set c $$a
[00:17] <Baal> Tcl: $one
[00:17] <arfer> .tcl set c [subst $$a]
[00:17] <Baal> Tcl: two
$$a resulted in an unexpected return value. Seemingly the innermost $ did not invoke substitution. This was forced by using subst command, yielding the expected result. _________________ I must have had nothing to do |
|
| Back to top |
|
 |
willyw Revered One
Joined: 15 Jan 2009 Posts: 1175
|
Posted: Sun Apr 05, 2009 7:31 pm Post subject: |
|
|
| arfer wrote: | Subst is a command that is used to force variable, command or backslash substitution where it might otherwise fail to occur.
Take the following example :-
[00:15] <arfer> .tcl set a one
[00:15] <Baal> Tcl: one
[00:16] <arfer> .tcl set $a two
[00:16] <Baal> Tcl: two
[00:17] <arfer> .tcl set c $$a
[00:17] <Baal> Tcl: $one
[00:17] <arfer> .tcl set c [subst $$a]
[00:17] <Baal> Tcl: two
$$a resulted in an unexpected return value. Seemingly the innermost $ did not invoke substitution. This was forced by using subst command, yielding the expected result. |
Thanks for the explanation. It still makes me do a double take though.
When you get a free moment, please have a look at your pm inbox here, and let me know what you think of what I'm trying to do. Again, I suspect there is a better way, but I need direction to get on the right path.
Thanks |
|
| Back to top |
|
 |
arfer Master

Joined: 26 Nov 2004 Posts: 436 Location: Manchester, UK
|
Posted: Sun Apr 05, 2009 11:07 pm Post subject: |
|
|
In pm, Willyw has asked me for help with code for a playback script. ie. a script that will remember the last few chat lines said on a channel and, if commanded to do so, will play back the lines by notice. In reality, this was the reason for the thread in the first place.
I thought that anybody following the thread may want to play around with and/or improve on the code, so I will paste it here.
Command syntax is !playback (bot flag o required).
Lines said by the bot (perhaps due to output from other scripts) are excluded as are !playback command lines.
The code below is preconfigured to recall the last 5 lines said in the channel #eggTCL.
Rehash/restart will clear the stored memory.
| Code: |
# *** configuration *** #
set vPlaybackMemory 5
set vPlaybackChannel #eggTCL
# *** code *** #
bind PUB o !playback pPlaybackOutput
bind PUBM - * pPlaybackStore
if {[info exists vPlaybackData]} {unset vPlaybackData}
proc pPlaybackOutput {nick uhost hand channel txt} {
global vPlaybackData vPlaybackMemory
for {set x 1} {$x <= $vPlaybackMemory} {incr x} {
if {[info exists vPlaybackData($x)]} {puthelp "NOTICE $nick :$vPlaybackData($x)"}
}
return 0
}
proc pPlaybackPromote {nick channel} {
if {[isop $nick $channel]} {
return "<@$nick\>"
} elseif {[isvoice $nick $channel]} {
return "<+$nick\>"
} else {return "<$nick\>"}
}
proc pPlaybackStore {nick uhost handle channel txt} {
global vPlaybackChannel vPlaybackData vPlaybackMemory
if {[string equal -nocase $channel $vPlaybackChannel]} {
if {![string match "!playback*" $txt]} {
if {![isbotnick $nick]} {
for {set x 1} {$x < $vPlaybackMemory} {incr x} {
if {[info exists vPlaybackData([expr {$x + 1}])]} {set vPlaybackData($x) $vPlaybackData([expr {$x + 1}])}
}
set vPlaybackData($vPlaybackMemory) "[pPlaybackPromote $nick $channel] $txt"
}
}
}
return 0
}
|
If I were to expand on the script, it would be to include other types of channel activity in the memory. ie. joins/parts/actions/modes etc. Outputting the memory automatically onjoin would probably be mega annoying so I avoided doing that. _________________ I must have had nothing to do |
|
| Back to top |
|
 |
|