Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search

[REBOL] Re: Context misery

From: joel:neely:fedex at: 5-Jun-2001 7:38

Hi! [Sanghabum--aol--com] wrote:
> Hi there, > > Could someone with a better grasp of context than me explain why this won't > work?---I think the problem is using a local variable in a DO: > > myfunc: func [BlockName [string!] > /local aa bb][ > > aa: copy [1 2 3] > bb: join BlockName ": copy aa" > print ["aa is " mold aa] > print ["bb is " mold bb] > do bb > ] > > When I run it I get: > >> myfunc "myblock" > aa is [1 2 3] > bb is "myblock: copy aa" > ** Script Error: aa has no value > ** Where: myfunc > ** Near: myblock: copy aa > >> >
The REBOL/Core Users' Guide says (page 3-11): Unless it is necessary, evaluating strings is generally not a good practice. Evaluating strings is less efficient than evaluating blocks, and the context of words in a string is not known. I strongly recommend taking that advice to heart! Trying to construct source code strings that DO what you want is tricky at best, and a potential source of highly subtle bugs at worst. That said, when you define BB using the expression bb: join BlockName ": copy aa" and then DO that string, REBOL has no idea that you intend for the two-letter token "aa" in the string to indicate the LOCAL word AA in the current function. (Without going into deep and opaque waters, just remember that there can be *many* words whose names are spelled the same!) To get the value that's in your local variable to be the value stored in the (possibly!) new variable named by the BLOCKNAME parameter, you will need to force evaluation of your local AA and then use that result to construct the string. One possible (and possibly clumsy) way to do this is:
>> myfunc: func [BlockName [string!] /local aa bb] [
[ aa: copy [1 2 3] [ bb: rejoin [BlockName ": copy " mold aa] [ print ["aa is " mold aa] [ print ["bb is " mold bb] [ do bb [ ]
>> myfunc "myblock"
aa is [1 2 3] bb is "myblock: copy [1 2 3]" == [1 2 3]
>> myblock
== [1 2 3]
But *please* remember the old joke: "Doc, it hurts when I do this!" "Well, then don't do that!" ;-)
> All I'm trying to do is create a variable dunamically based > on a name passed to a function. >
Why? If you can describe what you're trying to accomplish here, perhaps some of the old hands can offer some alternatives that won't be so tricky to deal with. For example... You can think of REBOL contexts as being like mini-dictionaries that map strings (the word names) to other values. (Now you see why different contexts can have words with the same name!) If you're trying to keep up with some data and you *really* need to associate values with names you can't know in advance, you could build your own "dictionary" as follows: fw: make object! [ storage: copy [] learn: func [ token [string!] value [any-type!] /local where ][ either none? find storage token [ append storage reduce [token value] ][ change/only storage value ] ] fetch: func [token [string!]] [ select storage token ] ]
>> fw/learn "myblock" copy [1 2 3]
== ["myblock" [1 2 3]]
>> fw/learn "yourblock" copy [4 5 6]
== ["myblock" [1 2 3] "yourblock" [4 5 6]]
>> fw/learn "anyblock" [9 8 7]
== ["myblock" [1 2 3] "yourblock" [4 5 6] "anyblock" [9 8 7]]
>> fw/fetch "myblock"
== [1 2 3] This is just a Q&D sample; an obvious improvement is to have LEARN return the VALUE argument as its result to facilitate embedding in larger expressions. Implementing that, and any other improvements, is left as an exercise to the reader! ;-) Hope this helps! -jn- ------------------------------------------------------------ Programming languages: compact, powerful, simple ... Pick any two! joel'dot'neely'at'fedex'dot'com