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

[REBOL] Re: Block Creation Re:

From: joel:neely:fedex at: 19-Oct-2000 11:29

Hello, Carl and list, Every time I try to verbalize what happens in cases such as: rebol [] for test1 1 5 1 [ block1: [] insert block1 "text1" ] I become very frustrated with myself. I end up with remarks that are far more complex than my mental concept of what's happening. I take that to mean that either I can't handle powerful languages (such as American English or REBOL ;-) very well, OR that I'm going about the explanation the wrong way. Obviously, I'd prefer the second of these! Therefore, please let me know what you think of the following stepwise description of how REBOL handles literal series values in contexts such as the above. I'll use blocks throughout, but any series type should follow the same thought process. In all of these cases, the word 'a is made to refer to a block which is subsequently modified (via 'a). The effect of the modification can be seen via other ways to get to the block. 1) There can be more than one reference to the same series.
>> b: [] == [] >> a: b == [] >> append a "hi" == ["hi"] >> b == ["hi"]
2) Any series can have multiple references to it, regardless of how it is originally created.
>> b: make block! 0 == [] >> a: b == [] >> append a "hi" == ["hi"] >> b == ["hi"]
3) This is not an issue of variables; a series contained by another series still behaves this way.
>> b: [[]] == [[]] >> a: b/1 == [] >> append a "hi" == ["hi"] >> b == [["hi"]]
4) When we ask REBOL to DO a block, all expressions in the block are evaluated, with the last of these values serving as the value of the entire block evaluation.
>> b: [1 + 1 2 + 2 3 + 3] == [1 + 1 2 + 2 3 + 3] >> do b == 6
5) This is also true when the expressions of the DOne block have (or represent) series values.
>> b: [1 + 1 "Hi" []] == [1 + 1 "Hi" []] >> do b == []
6) When the result of DOing a block is a series value, we can make another word refer to that value, with the same behavior as in points 1, 2, and 3 above.
>> b: [[]] == [[]] >> a: do b == [] >> append a "hi" == ["hi"] >> b == [["hi"]] >> do b == ["hi"]
7) If we get tired of writing "do..." repeatedly, REBOL allows us to create values that (in effect) DO themselves.
>> b: to-paren [[]] == ([]) >> a: b == [] >> append a "hi" == ["hi"] >> :b == (["hi"]) >> b == ["hi"]
8) We can make such an automatically-done value in other ways.
>> b: does [[]] >> a: b == [] >> append a "hi" == ["hi"] >> b == ["hi"] >> source b b: func [][["hi"]]
9) If that last line above was a surprise, just remember that DOES is simply a shortcut for creating a function that has no arguments and no local words.
>> source does
does: func [ {Defines a function that has no arguments or locals.} [catch] body [block!] "The body block of the function" ][ throw-on-error [make function! [] body] ] 10) This means that we can create such a function "by hand".
>> b: func [] [[]] >> a: b == [] >> append a "hi" == ["hi"] >> b == ["hi"] >> source b b: func [][["hi"]]
11) Note that the change above had nothing to do with the fact that we used a function; it resulted from having a reference to the literal block returned as the result of evaluating another block.
>> b: [[]] == [[]] >> a: loop 3 b == [] >> append a "hi" == ["hi"] >> b == [["hi"]]
12) A "chain of references" to a series may be created by passing such references from "hand to hand". The variables (or other forms) of these references don't matter -- only that the references all refer to the same series.
>> b: [[]] == [[]] >> a: first b == [] >> c: a == [] >> d: reduce ["boing" c] == ["boing" []] >> e: select d "boing" == [] >> append e "hi" == ["hi"] >> a == ["hi"] >> b == [["hi"]]
13) It also doesn't matter where the modifications are done, only that a shared series reference is being modified.
>> b: func [/local bb] [bb: [] append bb "hi"] >> a: b == ["hi"] >> append a " there!" == ["hi" " there!"] >> source b
b: func [/local bb][bb: ["hi" " there!"] append bb "hi"] 14) All of this means that b: func [/local bb] [b: [] append bb "hi"] is actually equivalent to b: func [][[] append first second :b "hi"] (assuming that you know that SECOND :B is a way to get to the block that is the body of B, of course!)
>> b: func [][[] append first second :b "hi"] >> b == ["hi"] >> b == ["hi" "hi"] >> b == ["hi" "hi" "hi"] >> b: func [/local bb] [bb: [] append bb "hi"] >> b == ["hi"] >> b == ["hi" "hi"] >> b == ["hi" "hi" "hi"]
14) Every time a series is created "from scratch" it is a different series than any previously existing series.
>> b: make block! [[]] == [[]] >> a: b/1 == [] >> append a "hi" == ["hi"] >> b == [["hi"]] >> b: make block! [[]] == [[]] >> b == [[]] >> a == ["hi"]
15) The block that constitutes the body of a function (and all literal values in it!) is created when FUNC is evaluated.
>> source-code: [b: func [/local bb] [bb: [] append bb "hi"]]
== [b: func [/local bb] [bb: [] append bb "hi"]]
>> do source-code >> source b
b: func [/local bb][bb: [] append bb "hi"]
>> b
== ["hi"]
>> b
== ["hi" "hi"]
>> b
== ["hi" "hi" "hi"]
>> source b
b: func [/local bb][bb: ["hi" "hi" "hi"] append bb "hi"]
>> do source-code >> source b
b: func [/local bb][bb: [] append bb "hi"]
>> b
== ["hi"] When we ask REBOL to DO SOURCE-CODE again, the function is re- created from the supplied source code, which means that the second value of its body is (once again) an empty block. One could go on in this vein, but that's more than enough for now. Does this kind of progression make sense to anyone else as a way to explain why we get the surprising-the-first-time-you-see-it behavior of literal blocks? -jn- -- ; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677 REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] { | e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]