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

append

 [1/6] from: fantam::mailandnews::com at: 14-Aug-2000 17:01


Hello all, In the following script, 'list-dirs is a function that returns the directory tree under the directory specified as an argument. On WinNT, using REBOL/Core 2.4.24.3.1, that script will throw an error when it encounters a directory that has a dot in its name (for example, "temp.old"). Furthermore, the error is thrown only if that directory is a second level sub-directory of the argument (for example %/c/temp/temp1/temp.old and not "%/c/temp/temp.old"). The most confusing thing is that if I remove the local definition of 'dirtree in the func spec, no error is thrown at all. I do not understand what is happening. REBOL [] dir: %/c/temp/ count: 0 list-dirs: func [ "returns dir tree as block" dir [file!] "root dir" /local dirtree [block!] ] [ if count = 0 [dirtree: make block! 100] count: count + 1 foreach name read dir [ if dir? dir/:name [ append dirtree dir/:name list-dirs dir/:name ] ] dirtree ] print list-dirs dir halt -- Fantam

 [2/6] from: rebol:techscribe at: 14-Aug-2000 10:42


Hi Fantam, you're shooting yourself in the foot. 1. The solution
>> list-dirs: func [ dir [file!] "root dir" /local dirtree ] [
[ if count = 0 [dirtree: make block! 100] [ count: count + 1 [ print ["Count: " count "type? dirtree" type? dirtree] [ foreach name read dir [ [ if dir? dir/:name [ [ append dirtree dir/:name [ list-dirs dir/:name [ ] [ ] [ dirtree [ ]
>> >> list-dirs %.
Count: 1 type? dirtree block Count: 2 type? dirtree none ** Script Error: append expected series argument of type: series port. ** Where: append dirtree dir/:name list-dirs dir/:name I modified your function slightly. Most importantly I added a print statement before the foreach loop: print ["Count: " count "type? dirtree" type? dirtree] As you can see this print statement reports that upon the first recursive call of list-dirs (count = 2), dirtree is set to none, it is not a block:
>> list-dirs %.
Count: 1 type? dirtree block Count: 2 type? dirtree none Therefore you get an error message, complaining that REBOL cannot append to a none value: ** Script Error: append expected series argument of type: series port. ** Where: append dirtree dir/:name a) By making count a global word and setting its value to 1 in list-dirs, you are preventing dirtree from being set to a block value each time list-dirs is called. b) By making dirtree a local word you force it to be initialized to none at each call to list-dirs, also during recursive calls. So, when list-dirs is entered recursively, dirtree is set to none by REBOL, because it is declared a local word (the [block!] expression behind the word does not have any effect, this notation is only effective for parameters, but not for local words), count was previously set to 1, and therefore dirtree is not being set to a block. That generates the error message documented above. 2. A few points you wrote:
>script will throw an error
1. Note what REBOL reports as an error. Sometimes that information can be helpful!
>when it encounters a directory that has a dot in its name (for >example, "temp.old"). Furthermore, the error is thrown only if that >directory is a second level sub-directory of the argument (for example >"%/c/temp/temp1/temp.old" and not "%/c/temp/temp.old").
2. Does the following code work?
>> x: [] >> name: %a.b/ >> dir: %c/d/e.f/ >> append x dir/:name
== [%c/d/e.f/a.b/]
>The most confusing thing is that if I remove the local definition of >'dirtree in the func spec,
3. What's the [block!] doing after dirtree?
>> f: func [/local dirtree [block!]] [ print type? dirtree] >> f
none It certainly has no influence on the type of dirtree! Hope this helps, ;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [3/6] from: galtbarber:mailandnews at: 14-Aug-2000 14:28


Hola, Fantam! /local dirtree [block!] as far as I know, you only get to declare the type of params passed to be checked, not the type of a local var. as somebody put it, values are type-checked, not variables, so it is even more reliable. Here is the error I got when I ran what you posted: ** Script Error: append expected series argument of type: series port. ** Where: append dirtree dir/:name list-dirs dir/:name It appears that on the second call, when count = 1, then the local dirtree is not initialized, and Rebol does not have a type for its unset value. Therefore it complains about the type not being series value. Obviously, if you remove the local declaration of dirtree, then a global one works better. It even accumulates all the whole tree. But this one works without needing any global variables: get-dirtree: func [ "returns directory tree as block" startdir [file!] "starting directory" /local dirtree recursive-dirlist ][ dirtree: make block! 100 recursive-dirlist: func [ dir [file!] ][ foreach name read dir [ if dir? dir/:name [ append dirtree dir/:name recursive-dirlist dir/:name ] ] ] recursive-dirlist startdir dirtree ] dir: %/c/temp/ print get-dirtree dir This is a relatively simple example, but I have often found that it is better to separate the pure recursive function from the setup stuff that is actually invoked during normal usage. This simple function doesn't really require much setup, though, so you can just do this if you want a pure-recursive: get-dirtree: func [ "returns directory tree as block" dir [file!] "starting directory" dirtree [block!] ][ foreach name read dir [ if dir? dir/:name [ append dirtree dir/:name get-dirtree dir/:name dirtree ] ] dirtree ] dir: %/c/temp/ print get-dirtree dir copy [] --------------------------------- You see, you just have to always remember to initialize and pass in the empty result block. -Galt

 [4/6] from: rebol:techscribe at: 14-Aug-2000 15:10


Hi Galt, a few minor comments: you wrote: [snipped correct and useful insights]
>It appears that on the second call, when >count = 1, then the local dirtree is not initialized,
Actually, local words are initialized to the value none (as are refinements):
>> f: func [/local word] [ print word ] >> f
none
>and Rebol does not have a type for its unset value.
The type of unset words is unset!:
>> type? ;- there ain't nothin' here for type?
== unset!
>Therefore it complains about the type not being series value.
Therefore: i.e. because the value of dirtree is none, and none's type is none!, which is not one of the types required by append. If the word was indeed unset, then you would get a different error:
>> f: func [/local word] [ unset 'word append word "something to append" ] >> f
** Script Error: word has no value. ** Where: append word "something to append" Hope this helps. ;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [5/6] from: fantam:mailandnews at: 16-Aug-2000 18:31


I see. Thanks. Also, I thought that when you create a word within the body of a function without declaring it as local, it would still be local, and not a global one, as it really is. daniel
> Hi Fantam, > you're shooting yourself in the foot.
<<quoted lines omitted: 69>>
> http://www.REBOLpress.com > visit me at http://www.TechScribe.com
-- Fantam

 [6/6] from: rebol:techscribe at: 16-Aug-2000 10:35


Hi Daniel, you wrote:
>Also, I thought that when you create a word within the body of a function
without
>declaring it as local, it would still be local, and not a global one, >as it really is.
You're right. A word declared in the body of a function is indeed global, unless it is declared /local or declared local to a use context. If this was not so, we would need a /global flag instead of a /local flag for function declarations. In contrast, a word created in the body of an object using the set-word! notation (a: "some value") is local to the object's context. To create global words from within an object context use set (set 'a "some value"). o: make object! [ a: "this word is local to the object referenced by o." set 'b "this word is global." ] Hope this helps, ;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

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