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

to-char

 [1/25] from: izkata:aol at: 9-Feb-2002 17:59


How do you use the to-char function? I've tried everything I can think of. Daniel S.

 [2/25] from: brett:codeconscious at: 11-Feb-2002 9:56


Not sure what you want to do so here are a couple of possibilities: to-char "*" to-char 42 going the other way: to-integer #"^-" Brett.

 [3/25] from: izkata:aol at: 10-Feb-2002 21:05


sorry, I'm not used to the harder stuff like parsing, yadda, yadda, yadda. What I'm looking for is a function/native that will change a word into a block of characters, for example: tochar "Hello" Word: [ H e l l o ] Daniel S

 [4/25] from: brett::codeconscious::com at: 11-Feb-2002 13:30


Read up on series in the manual. A string is a series. A block is a series. For example, first "Hello" pick "Hello" 3 repeat a-char "Hello" [print a-char] If you need the characters seperately in a block: block-of-char: copy [] repeat a-char "Hello" [ append block-of-char a-char ] Now perhaps you can help me. What does "yadda" actually mean? Brett.

 [5/25] from: philb:upnaway at: 11-Feb-2002 11:27


Hi Daniel, try something like cb: copy [] foreach lv-char "abcd" [append cb lv-char] probe cb just need to wrap it in a function. Cheers Phil === Original Message === sorry, I'm not used to the harder stuff like parsing, yadda, yadda, yadda. What I'm looking for is a function/native that will change a word into a block of characters, for example: tochar "Hello" Word: [ H e l l o ] Daniel S

 [6/25] from: vonj:peoplepc at: 10-Feb-2002 21:24


It's indicative of blah, blah, blah

 [7/25] from: carl:cybercraft at: 11-Feb-2002 17:47


On 11-Feb-02, [Izkata--aol--com] wrote:
> sorry, I'm not used to the harder stuff like > parsing, yadda, yadda, yadda.
<<quoted lines omitted: 9>>
> o > ]
Hi Daniel, I notice Brett has just posted similar stuff to the following, but this is what I came up with anyway... This function should do what you want... to-chars: func [str /local word][ word: copy [] forall str [append word str/1] word ]
>> to-chars "hello"
== [#"h" #"e" #"l" #"l" #"o"]
>> to-chars "goodbye"
== [#"g" #"o" #"o" #"d" #"b" #"y" #"e"] However, depending on what you're doing, you may be able to get the results you want without needing to convert a string to a block, as a string is already a series of characters. So, the following gives the same results...
>> str: "hello"
== "hello"
>> str/2
== #"e"
>> word: to-chars str
== [#"h" #"e" #"l" #"l" #"o"]
>> word/2
== #"e" HTH. -- Carl Read

 [8/25] from: izkata:aol at: 11-Feb-2002 11:42


I've looked at all the responses so far, and it's almost what I wanted. Heres a better example: to-charblock: "Hi" would make: block: [ H i ] then, H: [print "*** **** ****"] i: [print "*** iiii"] so, do block *** **** **** *** iiii I am going to use a combination of * and spaces to make a mouth that would 'talk' to you. I am going to try what was suggested, though. Daniel S.

 [9/25] from: jason:cunliffe:verizon at: 10-Feb-2002 23:37


; Is this what you want? to-charblock: func[aword [string!] /local charblock letter][ charblock: [] clear charblock foreach letter aword [ append charblock letter ] return charblock ] h: to-charblock "hello" ; to access >> print h/1 etc.. hth ./Jason

 [10/25] from: joel:neely:fedex at: 11-Feb-2002 20:40


Hi, Jason, Small kibitz... Jason Cunliffe wrote:
> ; Is this what you want? > to-charblock: func[aword [string!] /local charblock letter][
<<quoted lines omitted: 5>>
> return charblock > ]
Would either charblock: copy [] or charblock: clear [] work as well for you? -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;

 [11/25] from: jason:cunliffe:verizon at: 12-Feb-2002 0:20


> Would either > > charblock: copy [] > > or > > charblock: clear [] > > work as well for you?
Hi Joel Yes - just hasty cutnpaste from console while trying out some other stuff. I am curious what preferences/differences are between: copy [] and clear [] thanks ./Jason

 [12/25] from: carl:cybercraft at: 12-Feb-2002 19:24


Hi again Daniel, On 12-Feb-02, [Izkata--aol--com] wrote:
> I've looked at all the responses so far, and > it's almost what I wanted. Heres a better example:
<<quoted lines omitted: 4>>
> i > ]
Ah - you actually want 'H and 'i there to be REBOL "word"s, not REBOL char acters - except they're just 1-letter words.
> then, > H: [print "*** **** ****"]
<<quoted lines omitted: 3>>
> *** **** **** > *** iiii
As you have it there, the 'do wouldn't work as you expect, as this sesion at the REBOL Console shows...
>> block: [H i]
== [H i]
>> H: [print "*** **** ****"]
== [print "*** **** ****"]
>> i: [print "*** iiii"]
== [print "*** iiii"]
>> do block
== [print "*** iiii"] Which isn't the result you want. However, if 'H and 'i are made to do their block (pun not intended:) using 'does, you get what you want...
>> H: does [print "*** **** ****"] >> i: does [print "*** iiii"] >> do block
*** **** **** *** iiii (Testing stuff a bit at a time at the Console is a good way to work things out.) 'does turns 'H and 'i into functions (without any arguments), the difference being you'll get the result returned by the function, whereas when they were just blocks, the block is what you get. Um, this probably explains it better...
>> a-block: [print "something"]
== [print "something"]
>> a-block
== [print "something"]
>> a-block: does [print "something"] >> a-block
something Finally, to get words instead of characters into the block, you can use 'to-word. Except it can't convert a character directly to a word, (ie, an #"H". That's a character, whereas "H" is a string.), so you need to convert each character in your string into a 1-character string before you can convert it into a word. I know it sounds convoluted, but the function to do what you want is a lot shorter than this paragraph you'll be happy to hear. (: ... to-charblock: func [str [string!] /local blk][ blk: copy [] foreach letter str [append blk to-word to-string letter] blk ] You should be able to cut and paste that function directly into the Console to test it, and assuming you can, it can be used to give these results (as long as you've also entered the 'H and 'i functions first in the way I suggested above)...
>> block: to-charblock "Hi"
== [H i]
>> do block
*** **** **** *** iiii Have we got it right now? Though don't be afraid to say no if we haven't - it's what the list is for.
> I am going to use a combination of > * and spaces to make a mouth that would > 'talk' to you. > I am going to try what was suggested, though. > Daniel S.
-- Carl Read

 [13/25] from: carl:cybercraft at: 12-Feb-2002 18:14


Hi Jason, Just a note to point out you didn't need to make 'letter local in your function as it's automatically made local to 'foreach's block. ie...
>> foreach letter "abc" [print letter]
a b c
>> print letter
** Script Error: letter has no value ** Near: print letter Same with 'for and so on. Even so, for sanity's sake I don't recomend you do much of the following kind of stuff...
>> for n 1 3 1 [prin [n ": "] for n 1 3 1 [prin n] print ""]
1 : 123 2 : 123 3 : 123 (: On 11-Feb-02, Jason Cunliffe wrote:
> ; Is this what you want? > to-charblock: func[aword [string!] /local charblock letter][
<<quoted lines omitted: 9>>
> hth > ./Jason
-- Carl Read

 [14/25] from: joel:neely:fedex at: 12-Feb-2002 7:12


Hi, Jason, Forgive me if I over-explain. I don't mean to insult your intelligence/experience. This kind of question comes up periodically, so I thought I'd cover all the basics in case any newcomers to the list are puzzled by this (or related) issues. Jason Cunliffe wrote:
> I am curious what preferences/differences are between: > > copy [] and clear [] >
(All of my remarks below actually apply to series values in general, not just blocks. However, the term "block" is nicer to write about, because its singular and plural forms are easy to distinguish and pronounce, unlike the term "series". For that -- fairly feeble -- reason I'll stick with "block".) The differences have to do with "current size" versus "capacity" and the persistence of literal block values. If you type either of the above at the console, you get an empty block, and that's just about the end of the story. Embedding either expression inside a block that is DOne or inside a function gets quite a different effect. First, let's talk about "current size" and "capacity". A block is like an array; it contains a specific set of values in a specific order. But REBOL blocks are flexible; we can extend a block with more values or remove values from a block. When first created, a block has some (optional) content, but also can have additional "growing room" already allocated but not yet in use. When we insert a value into a block, we use up one "slot" of that additional space, assuming that there is some still left. Once there's no more growing room, the interpreter must allocate enough memory for the new (expanded) state of the block, and then copy all of the old and new data into the new space. Therefore, when creating or expanding a block, there's a tradeoff between only providing enough room for the current content (thus increasing the probability that some copying will need to be done later) versus providing lots of growing room (thus increasing the probability that memory is tied up "just in case" but never used, and possibly interfering with other uses). I don't know what the exact (current) policies and defaults are; perhaps someone else (RT?) can shed more light on that mystery. I *do* know that a literal block [] appearing in a REBOL expression like fleegle: [] gets translated into a block value with no (initial) content and only limited growing room (maybe none? anybody know?). If we know that we are going to be growing a block, we can ask in advance for a certain capacity, even if we're not immediately populating it with data, by writing something like fleegle: make block! 1000 to indicate how much space we think we'll need. To see what a difference that can make, consider the following expressions and the time required to evaluate them (I simply wrapped each one as follows: t: now/time/precise ... now/time/precise - t to get the times.) foo: [] repeat i 10000 [insert tail foo i] ==> 0:00:00.77 foo: [] repeat i 100000 [insert tail foo i] ==> 0:00:58.01 Increasing the number of iterations by a factor of ten takes *much* more than ten times as long, because the overhead of allocating new space and copying values takes progressively more of the total time. (I'd expect it to be quadratic; ignoring the jitter due to garbage collection, that appears to be the case. Again, perhaps someone can confirm or deny.) foo: make block! 100000 repeat i 100000 [insert tail foo i] ==> 0:00:02.31 If we pre-allocate the amount of storage we'll need, then the interpreter doesn't have to waste time shuffling things around to make more room. A *huge* improvement! foo: clear foo repeat i 100000 [insert tail foo i] ==> 0:00:01.98 This case shows that CLEAR removes the content, but leaves the capacity unchanged. Therefore we can re-use the space with no time penalty. baz: clear foo repeat i 100000 [insert tail baz i] ==> 0:00:01.97 Likewise, we can get at that space through multiple references with the same benefit. Now let's talk about persistence. The simplest example I can think of is this one:
>> to-do: [foo: [] insert tail foo "Hi!" print foo]
== [foo: [] insert tail foo "Hi!" print foo]
>> do to-do
Hi! No surprise thus far, but look at what happens next...
>> to-do
== [foo: ["Hi!"] insert tail foo "Hi!" print foo]
>> do to-do
Hi! Hi!
>> foo
== ["Hi!" "Hi!"]
>> to-do
== [foo: ["Hi!" "Hi!"] insert tail foo "Hi!" print foo] The key is to recognize that TO-DO (initially) *isn't* saying set FOO to refer to an empty block but rather is saying set FOO to refer to *this* block -- the second element in TO-DO is the *this* part. Subsequent changes via the reference in FOO affect the underlying data series, regardless of how many other references we may have to it -- including the one that's the second element of TO-DO! Therefore, the second element of TO-DO is being continually changed. The same thing can happen with a literal block appears in the (source for the) body of a function. If we don't want that block to keep accumulating the effects of expressions that the interpreter evaluates subsequently, we need to make sure that our variable is set to an empty block each time. There are three obvious ways to do this (and several un-obvious ways as well! ;-) foo: copy [] asks for a clone of its argument block; it doesn't alter that argument block. Unless you do some fairly contorted things (which can be done!), evaluating that will produce an empty block every time. foo: make block! 1 (using whatever size you wish) explicitly asks the interpreter to construct a fresh block. This just looks clunkier for small cases, but is nicely explicit when you have a definite idea of how much space you'll need. If you *don't* know how much you'll need, and allocate too much "just in case", this version wastes memory. foo: clear [] explicitly asks the interpreter to empty out anything that might have accumulated from previous evaluations. It throws out the content, but doesn't change the allocated space. If you are repeatedly evaluating a function that constructs results of roughly similar size (e.g., building up strings used as output lines in a printable report), then this version allows the capacity of the underlying series to grow upwards as it is actually used. It avoids the overhead of COPYing or MAKEing a new block for each evaluation of the function, which is A Good Thing. However, if you have a single extreme case that builds up a huge value, this version will keep all of that space allocated, even if subsequent evaluations don't need it. The risk of tying up memory for no good reason is A Bad Thing, but you'll have to figure out on a case-by-case basis how big that risk actually is. Speaking of risk, I hope I haven't given you a two-ton answer to a five-ounce question! ;-) HTH! -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;

 [15/25] from: g:santilli:tiscalinet:it at: 12-Feb-2002 14:21


At 03.40 12/02/02, Joel wrote:
>> to-charblock: func[aword [string!] /local charblock letter][ >> charblock: []
<<quoted lines omitted: 10>>
> charblock: clear [] >work as well for you?
Oh and BTW, in the second case (and the one used above) you will have problems if you write something like: a: to-charblock "123" b: to-charblock "456" (Just in case Jason doesn't know...) Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [16/25] from: joel:neely:fedex at: 12-Feb-2002 8:52


Hi, Gabriele, Gabriele Santilli wrote:
> >or > >
<<quoted lines omitted: 5>>
> a: to-charblock "123" > b: to-charblock "456"
In both cases, I got the following:
>> a: to-charblock "123"
== [#"1" #"2" #"3"]
>> b: to-charblock "456"
== [#"4" #"5" #"6"] What kinds of problems are you referring to? -jn-

 [17/25] from: rotenca:telvia:it at: 12-Feb-2002 18:16


Hi Joel,
> > Oh and BTW, in the second case (and the one used above) you will > > have problems if you write something like:
<<quoted lines omitted: 7>>
> >> b: to-charblock "456" > == [#"4" #"5" #"6"]
I think that Gabriele want to say this:
>> x: func[x] [head insert clear [] x] >> a: x 1
== [1]
>> b: x 2
== [2]
>> a
== [2] --- Ciao Romano

 [18/25] from: carl:cybercraft at: 13-Feb-2002 9:51


On 13-Feb-02, Joel Neely wrote:
> Hi, Gabriele, > Gabriele Santilli wrote:
<<quoted lines omitted: 17>>
> == [#"4" #"5" #"6"] > What kinds of problems are you referring to?
Romano was right (in his following mail) - 'a and 'b would be the same after doing the above. When I noticed there wasn't a 'copy with the block in to-charblock I checked it to see what would happen, expecting the blocks returned to just keep getting longer and longer. When they didn't, and seemed to be doing what was expected, I checked the function again and noticed the 'clear this time. I wondered about its use then, (instead of 'copy), but didn't look into it. The short answer to this (for newcomers) is it's better to use... a-block: copy [] within functions instead of... a-block: [] clear a-block Examples...
>> copy-block: func [a][b: copy [] append b a] >> a: copy-block 1
== [1]
>> b: copy-block 2
== [2]
>> a
== [1]
>> b
== [2]
>> clear-block: func [a][b: [] clear b append b a] >> c: clear-block 3
== [3]
>> d: clear-block 4
== [4]
>> c
== [4]
>> d
== [4] And finally, what happens with no 'copy or 'clear...
>> append-block: func [a][b: [] append b a] >> e: append-block 5
== [5]
>> f: append-block 6
== [5 6]
>> e
== [5 6]
>> f
== [5 6] -- Carl Read

 [19/25] from: atruter:hih:au at: 13-Feb-2002 12:06


Hi Joel,
> Forgive me if I over-explain. I don't mean to insult your > intelligence/experience. This kind of question comes up > periodically, so I thought I'd cover all the basics in case > any newcomers to the list are puzzled by this (or related) > issues.
I find your explanations much better than the (sometimes terse) RT doco. It certainly "brings things together" for me, keep up the good work! Regards, Ashley P.S. I think you have generated enough material for your own book on REBOL, I for one would buy if you ever publish ;)

 [20/25] from: jason:cunliffe:verizon at: 13-Feb-2002 15:31


From: "Joel Neely" <[joel--neely--fedex--com]>
> Forgive me if I over-explain. I don't mean to insult your > intelligence/experience. This kind of question comes up > periodically, so I thought I'd cover all the basics in case > any newcomers to the list are puzzled by this (or related) > issues.
Joel Thanks very much. Your explanation and the posts which followed were just what I was hoping for. So now let me ask an even more basic [FA] question: What is happening, what is the real meaning of someblock: [] What is going on when I call it within a function and then call the function repeatedly [when the previous values remain]. ie: why do I _really_ need clear or copy? Would like to see more helpful doc lookups for : and []
>> ? :
** Syntax Error: Invalid word-get -- : ** Near: (line 1) ? :
>> ? []
[] is a block
>> ? clear
USAGE: CLEAR series DESCRIPTION: Removes all values from the current index to the tail. Returns at tail. CLEAR is an action value. ARGUMENTS: series -- (Type: series port none) thanks ./Jason

 [21/25] from: carl:cybercraft at: 14-Feb-2002 12:46


On 14-Feb-02, Jason Cunliffe wrote:
> From: "Joel Neely" <[joel--neely--fedex--com]> >> Forgive me if I over-explain. I don't mean to insult your
<<quoted lines omitted: 5>>
> Thanks very much. Your explanation and the posts which followed were > just what I was hoping for.
I'll give it a go, though the terms I use may not all be comp-science perfect...
> So now let me ask an even more basic [FA] question:
A question for you - what's "FA"? (:
> What is happening, what is the real meaning of > someblock: []
An empty block is created, as is the word 'someblock, which points to (references) the block. If you now made another word to reference someblock, they would both be referencing the same block. A Console example...
>> someblock: []
== []
>> not-another-block: someblock
== []
>> append someblock "abc"
== ["abc"]
>> someblock
== ["abc"]
>> not-another-block
== ["abc"]
> What is going on when I call it within a function and then call the > function repeatedly [when the previous values remain]. ie: why do I > _really_ need clear or copy?
The reason can be seen in the above, in that it remains the same block. Meaning you haven't made a copy of the block. Continuing on with the above, this shows the difference 'copy makes...
>> another-block: copy someblock
== ["abc"]
>> append someblock "def"
== ["abc" "def"]
>> someblock
== ["abc" "def"]
>> another-block
== ["abc"]
> Would like to see more helpful doc lookups for : and []
The Core Guide on RT's site is very good here. (It's a full copy of the book version.) See the "series" and "block" sections, blocks being a subset of series.
>>> ? : > ** Syntax Error: Invalid word-get -- : > ** Near: (line 1) ? :
The ":" is just used to define a word - it's says "make this word reference what follows". In the case of series such as blocks and strings, the word is used as an index to the series. So words can be used thus...
>> append someblock ["ghi" "jkl"]
== ["abc" "def" "ghi" "jkl"] That adds two more strings to 'someblock...
>> someblock
== ["abc" "def" "ghi" "jkl"] 'next in the following looks at the block from the next value onwards from where 'someblock's index is pointing. (Which is the first value in the block.)
>> next someblock
== ["def" "ghi" "jkl"] And this creates the word 'a-word to reference the block at that second position...
>> a-word: next someblock
== ["def" "ghi" "jkl"]
>> a-word
== ["def" "ghi" "jkl"] And now to see what the words' indexes are...
>> index? someblock
== 1
>> index? a-word
== 2 And finally, proof (using the 'head word) that 'a-word can reference the full block...
>> head a-word
== ["abc" "def" "ghi" "jkl"]
>>> ? [] > [] is a block
Blocks are very inportant in REBOL, but they're quite a simple concept, being just a container for other stuff.
>>> ? clear > USAGE:
<<quoted lines omitted: 5>>
> ARGUMENTS: > series -- (Type: series port none)
Clear just empties a series of its values, (from the index-point onwards of the word you're using to reference it), and so the series still exists after a 'clear, its just empty, like "" is an empty string, or [] is an empty block. More on functions: A series is created when the function is first created and not each time the function is called, which is why what's in a series will persist from function-call to function-call unless you specifically clear it or make a copy of it. Whether to use 'copy or 'clear (or neither for that matter) will depend on the behaviour you want from the series. HTH, and that I've got it all more or less right. Others here will (I hope) correct me where I'm wrong. -- Carl Read

 [22/25] from: jason:cunliffe:verizon at: 13-Feb-2002 20:53


> > So now let me ask an even more basic [FA] question: > > A question for you - what's "FA"? (:
FA: "frequently asked" ; as in FAQ => why need to use copy [] ./Jason

 [23/25] from: izkata:aol at: 14-Feb-2002 8:56


Yes, this is it perfectly! I hadn't known about putting 'does in right there, which is why my other tests hadn't worked out. Thanks for the help! P.S, Why does it seem that the only time mail is ever sent to the mailing list is in the middle of the night (for me)? (Central time zone)

 [24/25] from: joel:neely:fedex at: 14-Feb-2002 9:08


Hi, Jason, Carl, and all... Sorry that the following is so long. I don't have time to write it in fewer words. English, combined with a bag of prior experience with other programming languages, is really a *TERRIBLE* medium for explaining REBOL!!! ;-) As always, I'll be happy for any corrections or useful revisions of this discussion. Carl Read wrote:
> > So now let me ask an even more basic [FA] question: > > A question for you - what's "FA"? (: >
FA as in FAQ
> > What is happening, what is the real meaning of > > > someblock: [] > > An empty block is created, as is the word 'someblock, which > points to (references) the block. >
I must respectfully disagree. The issue of when values are created is an entirely different discussion than the issue of what happens when those values are evaluated. There is not much documentation that separates out these issues, so this puzzle comes up in almost every REBOL programmer's path to enREBOLment. As I understand it, when REBOL *loads* a string of the form foo: <value> (where <value> is a single value such as a number, string, or block) it creates an internal REBOL structure (which can serve as both code and data, depending on how it is subsequently used). In that structure there is a distinct REBOL value for each syntactical element in the source string. However, to know some of the details, we have to know where that string came from. Console input to the interpreter is submitted to a "load-and-do" cycle which takes the input string, loads (translates) it into a REBOL structure, then DOes that structure. Starting with a fresh REBOL process, we can model that process as follows: REBOL/View 1.2.1.3.1 21-Jun-2001 ... more verbiage suppressed ... *** Obtain REBOL/View/Pro from http://www.rebol.com/view-sales.html
>> print foo
** Script Error: foo has no value ** Near: print foo (Just to show that REBOL has no preconceived notion of FOO...)
>> console-input-1: "foo: []"
== "foo: []"
>> length? console-input-1
== 7 The console input is a string of 7 characters.
>> console-struct-1: load console-input-1
== [foo: [] ]
>> length? console-struct-1
== 2 LOADing the console input produces a block containing two values.
>> type? console-struct-1/1
== set-word!
>> type? console-struct-1/2
== block! LOAD created a SET-WORD! value from the string "foo:" and created a block from the string "[]" and put those two values into a new block. The (empty at this point) block doesn't have any more baggage, but there's a hidden issue with the SET-WORD! value. Each REBOL word belongs to a context (known in other languages as an environment or other terms even less useful to us right now! ;-) I think of an environment as a dictionary that pairs the name of a word with a value (reference for some types), but that pairing is relevant only within that context. (If that last phrase is unclear, hang on; we'll try to shed more light on it Real Soon Now.) I think of the internal representation of a word as "containing" a reference to the string that is its name and a reference to its context. NB: THAT IS A DESCRIPTIVE MENTAL MODEL. THERE ARE MANY WAYS THAT THIS COULD ACTUALLY BE IMPLEMENTED; I DON'T KNOW WHICH OF THEM IS/ARE ACTUALLY USED IN THE VARIOUS FLAVORS OF REBOL. In order to create the SET-WORD! value for "foo:", it must have a context. For the above case, since there's nothing to specify otherwise, that will be the global context. So a word value is created with a name of "foo" and a reference to the global context; a new definition is added to the global context containing a word name of "foo" but with no associated value at this point. (AGAIN, THINK OF THIS AS METAPHORICAL.) Finally (whew! this guy is long-winded! ;-) we're ready to talk about the DO step.
>> do console-struct-1
== []
>> print foo >> print mold foo
[] DOing a block requires evaluating each value within the block. When evaluating a SET-WORD! the interpreter does something like the following (AGAIN, METAPHORICAL): 1) put the word in question "on hold"; 2) evaluate the following value/expression (let's not go into that too much right now) which in this case is a reference to a block; 3) evaluating a block (NOT the same as DOing the block!) simply yields a reference to that block; 4) take the word left on hold in (1) and find its context; 5) within that specific context/dictionary, alter the value slot associated with that word, so that now the value slot contains the value (or reference to ... yadda yadda) produced in (3); 6) in addition, the value from (3) now serves as the value for this entire process (in case this evaluation occurred within a larger evaluation -- the issue we skipped over in (2)). At this point, the interpreter would be able throw away a string typed into the console, and the block created from that string, since there are no surviving references to them. In the case of our little modeling exercise, that doesn't happen because we actually have words that are set to the string and block we're playing with. We'll keep them around for a little longer to make a point. Let's model the load-and-do cycle on another string (this time without so much verbiage):
>> console-input-2: "oof: foo"
== "oof: foo"
>> console-struct-2: load console-input-2
== [oof: foo ]
>> do console-struct-2
== [] There's a new word in the global context now. Its value (in that context) is set to refer to the *same* block that (global) FOO is set to. Let's keep modeling the load-and-do cycle...
>> console-input-3: "append oof 1"
== "append oof 1"
>> console-struct-3: load console-input-3
== [append oof 1 ]
>> do console-struct-3
== [1] I'm sure we can all describe that one, and would anticipate the result of cheating and looking at the actual words we're playing with in our model:
>> mold foo
== "[1]"
>> mold oof
== "[1]" However, ("Finally!" you're probably thinking ;-) now I can get to my first punch line. Let's go back and look at our input strings, and then look at the structures that represent those strings in REBOL internal form (with MOLDing and some added whitespace for clarity):
>> foreach thing reduce [
[ console-input-1 console-input-2 console-input-3 [ ][print mold thing] "foo: []" "oof: foo" "append oof 1"
>> foreach thing reduce [
[ console-struct-1 console-struct-2 console-struct-3 [ ][print mold thing] [foo: [1] ] [oof: foo ] [append oof 1 ] What's with the value of CONSOLE-STRUCT-1??? Remember that it originally contained two values -- a set-word! and an empty block (created empty at the time that CONSOLE-INPUT-1 was LOADed). And that's the key. DOing CONSOLE-STRUCT-1 didn't *create* the set-word nor the empty block. They were created when CONSOLE-INPUT-1 was LOADed. All that happened when CONSOLE-STRUCT-1 was DOne was that the value (in the global context) for FOO was set to (a reference to) the block which *already* existed and was referred to in the second position of CONSOLE-STRUCT-1. DOing CONSOLE-STRUCT-2 set (global) OOF (created when we LOADed CONSOLE-INPUT-2) to refer to that same block (still empty at that time). At that point there were three references to that block: the original reference in CONSOLE-STRUCT-1, in the global context for FOO, and in the global context for OOF. The first of those only remained in existence because of our modeling; if we simply typed the console input strings in at the prompt, the older strings and blocks would have already gone back to the recycling plant as soon as the next input was typed. Just to prove that these are three references to the same block, let's cheat on our model. We'll set OOF directly and see the consequences.
>> oof: "no block here!"
== "no block here!"
>> foreach thing reduce [
[ console-struct-1 console-struct-2 console-struct-3 [ ][print mold thing] [foo: [1] ] [oof: foo ] [append oof 1 ] Setting OOF to a new string (created when this new console input was loaded -- outside our model), we simply change the global dictionary definition for OOF to something else. We haven't altered the value with which OOF was associated before that point.
>> oof: append foo "I'm back!"
== [1 "I'm back!"] Now we've reSET the value of OOF to the value of an expression that *also* mutates the value to which FOO is set. Therefore, we now see the effect of that mutation through all references to that same value:
>> foreach thing reduce [
[ console-struct-1 console-struct-2 console-struct-3 [ ][print mold thing] [foo: [1 "I'm back!"] ] [oof: foo ] [append oof 1 ] With all of that in place, let's fast-forward to Carl's comments on functions:
> More on functions: A series is created when the function is > first created and not each time the function is called, which is > why what's in a series will persist from function-call to > function-call unless you specifically clear it or make a copy of > it. Whether to use 'copy or 'clear (or neither for that matter) > will depend on the behaviour you want from the series. >
I agree 100% with what Carl meant, but -- with apologies -- let me try to reword a little bit by continuing our modeling exercise.
>> console-input-4: "trick: func [/local foo] [foo: append [] 1]"
== "trick: func [/local foo] [foo: append [] 1]"
>> console-struct-4: load console-input-4
== [trick: func [/local foo] [foo: append [] 1] ]
>> do console-struct-4
Now there's a global word TRICK which is set to a FUNCTION! value. The SECOND part of a FUNCTION! value is a block -- the "body" of the function.
>> second :trick
== [foo: append [] 1] When was that FUNCTION! value created? When CONSOLE-STRUCT-4 was DOne. When FUNC is applied to two blocks, it constructs a new FUNCTION! value with a process something like this: 1) create a new (empty) context; 2) add to that context every argument and refinement in the first block given to FUNC; 3) make a deep copy of the second block offered to FUNC, but whenever a word appears in that copy that is also in the first block, change the context of the word IN THE COPY to be the context created in (2); 4) create a new FUNCTION! value that is based on the results of (2) and (3), and return that FUNCTION! as the value of (this invocation of) FUNC to whatever caused FUNC to be invoked. The third element in the body of TRICK is (at this moment!) an empty block. It is there because LOAD created an empty block as the third element of the fourth element of CONSOLE-STRUCT-4, and then FUNC copied that empty block at (3) to create the third element of the block that serves as the body of the FUNCTION! created in (4). So, at this moment, the third element of the body of TRICK is an empty block created by copying an empty block created by LOADing a string that contained -- in part -- a #"[" followed by a #"]". To save me some typing and you some reading, let's call that block ~HERBIE~ (the weird punctuation is to remind us that this is only our conversational name for something, it is not REBOL terminology nor notation). Now when we evaluate the (global) TRICK, we get the same behavior that we were discussing earlier:
>> trick
== [1]
>> trick
== [1 1]
>> trick
== [1 1 1] The reason is that -- in the body of TRICK -- the (local to TRICK) word FOO is set to the value of an expression that mutates its first argument, which is ~HERBIE~. ~HERBIE~ started off empty when the function was created. Each time that the function is evaluated, the (local to TRICK) word FOO is set to the value of an expression that modified ~HERBIE~. Since the third element of TRICK's body is a reference to ~HERBIE~, we will see the effects of those mutations when we look at TRICK's body.
>> second :trick
== [foo: append [1 1 1] 1] Since TRICK's body was created by sort-of-copying a block that's still in CONSOLE-STRUCT-4, we *will*not* see the effects of the mutations there.
>> console-struct-4
== [trick: func [/local foo] [foo: append [] 1] ] Since the first element of TRICK's body is a word that has a different context than the global one, all of this SETting of that word has no effect on the global FOO as seen below:
>> foo
== [1 "I'm back!"] We can "tunnel" into that the body of TRICK and see the value of TRICK's local FOO as follows:
>> get first second :trick
== [1 1 1] As with our console input modeling above, there's still a chain of references to ~HERBIE~ so the value of ~HERBIE~ persists. And, since the body of TRICK is just a block, we can do block operations on it:
>> poke second :trick 3 [2]
== [foo: append [2] 1] Now the body of FOO no longer contains a reference to ~HERBIE~ because I POKEd a different value into the place where that reference to ~HERBIE~ used to be. However, there's still another reference to ~HERBIE~
>> get first second :trick
== [1 1 1] But look what happens when I pull another TRICK ...
>> trick
== [2 1]
>> second :trick
== [foo: append [2 1] 1]
>> get first second :trick
== [2 1] I've killed ~HERBIE~ !!! (Good thing he was only a virtual name, or I'd be arrested! ;-) Now both the (local to TRICK) word FOO and the third element of TRICK's body refer to a new block. OBTW, that block was created when I typed the string "poke second :trick 3 [2]" into the console and REBOL LOADed it. It was then mutated when the body of TRICK was evaluated. If you've read this far, you deserve an Olympic medal for the marathon!!! The reason for using COPY in front of a "literal" block inside a REBOL function would be to prevent mutations through a reference to that block from persisting -- i.e. you want a fresh instance of that block's content every time. I know that the above discussion was painful and laborious to read, but I hope it makes clear that there's already some COPYing going on. Knowing *when* the COPYing happens and *what* values are COPYed makes a lot of difference IMHO. As for CLEAR, it simple discards the content of a series, but doesn't replace the series itself.
>> foo
== [1 "I'm back!"]
>> oof
== [1 "I'm back!"]
>> clear foo
== []
>> oof
== [] so that OOF and FOO still both refer to the same series, its just that a (particularly severe!) mutation to that series's value occurred. The consequence of THAT fact is illustrated with these two little tweedles :
>> dee: func [/local foo] [foo: append copy [] 1] >> dum: func [/local foo] [foo: append clear [] 1]
I hope that I've belabored my model to the point that all of the following now make sense to you, most admirable and persistent reader!
>> a: dee
== [1]
>> b: dee
== [1]
>> c: dum
== [1]
>> d: dum
== [1]
>> append a 2
== [1 2]
>> b
== [1]
>> second :dee
== [foo: append copy [] 1]
>> append c 2
== [1 2]
>> d
== [1 2]
>> second :dum
== [foo: append clear [1 2] 1]
>> e: dee
== [1]
>> f: dum
== [1]
>> second :dum
== [foo: append clear [1] 1] Or, if you'll pardon the pun, I hope that it's all CLEAR now! -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;

 [25/25] from: g:santilli:tiscalinet:it at: 14-Feb-2002 16:02


At 15.52 12/02/02, you wrote:
>What kinds of problems are you referring to?
With CLEAR:
>> a: to-charblock "123"
== [#"1" #"2" #"3"]
>> b: to-charblock "456"
== [#"4" #"5" #"6"]
>> a
== [#"4" #"5" #"6"] which I think is not what Jason would expect. Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted