• Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

AltME groups: search

Help · search scripts · search articles · search mailing list

results summary

worldhits
r4wp5907
r3wp58701
total:64608

results window for this page: [start: 26801 end: 26900]

world-name: r3wp

Group: !REBOL3-OLD1 ... [web-public]
Anton:
2-Sep-2006
Brian, delimit function: 

- For long-term readability, I would avoid reusing 'copy as a variable. 
I suggest 'result, even if it means using another word.

- I understand with the /copy refinement you are able to get more 
speed in creating the result block, but I think I would prefer just 
letting the user copy the data before passing to delimit. This would 
give a simpler implementation, easier to read again.

I don't wish to devalue your effort in getting this version - I did 
a similar thing optimizing conjoin - made it harder to read.
BrianH:
5-Sep-2006
I was just using the same refinement /copy that bind uses, but I 
agree that its reuse as a local variable isn't very readable. I should 
use /local like my conjoin does. Speaking of conjoin, what do you 
think of the one above? The only speedup I can see to do is to replace 
the insert reduce with four inserts, but otherwise it seems useful.
Anton:
5-Sep-2006
A function which joins values into a string might be named CONFORM.
Anton:
5-Sep-2006
Brian, I've read carefully through your conjoin (but haven't tested 
yet), and I like it, except for *one* thing - I would reverse the 
order of the data and delimiter arguments. (Actually, I'm searching 
now for a better word than "delimit". It doesn't quite seem right.)
Anton:
6-Sep-2006
Brian, your last version of CONJOIN, a minor problem:

** Script Error: pick expected index argument of type: number logic 
pair
** Where: conjoin
** Near: pick [
    [local: insert local reduce [delimiter {"} first data {"}]]
    [local: insert insert local delimiter first ...
Anton:
6-Sep-2006
Brian, if you are going to use a get-word for safety with the first 
value, ie.  [form :local] , then it's probably consistent to be safe 
with the rest of the data too ? eg. instead of
	insert local first data
use:
	insert local pick data 1
Anton:
6-Sep-2006
; Brian H's version corrected by Anton:
; - LOCAL starts at its tail
; - PICK converted to EITHER (PICK doesn't work with NONE)
; - /QUOTED applied to first value
conjoin: func [

 "Join the values in a block together with a delimiting PAD value."
	data [any-block!] "The series to join"
	pad "The value to put into the series"
	/only "Inserts a series PAD as a series."
	/quoted "Puts string values in quotes."
	/local ; <- used to track tail of the result as we build it
] [
	if empty? data [return make data 0]

 local: tail either series? local: first data [copy local] [form :local]

 if all [quoted any-string? local][local: insert tail insert head 
 local {"} {"}] ; quote the first value
	; <- (local should be at its tail at this point)
	while [not empty? data: next data] either any-string? local [
		either quoted [

   [local: insert insert insert insert local pad {"} first data {"}]
		][
			[local: insert insert local pad first data]
		]
	] [
		either only [
			[local: insert insert/only local pad first data]
		][
			[local: insert insert local pad first data]
		]
	]
	head local
]

; test
conjoin [] ""
conjoin [] ","
conjoin [1 2 3] '|
conjoin [[1] 2 3] '|
conjoin ["one" 2 3] ", "
conjoin [["one"] 2 3] '|
conjoin [1 2 [3]] [pad]
conjoin [[1] 2 [3]] [pad]
conjoin/only [[1] 2 [3]] [pad]
conjoin/only [[1] 2 [3]] 'pad

conjoin/quoted [1 2 3] '|
conjoin/quoted [[1] 2 3] '|
conjoin ["one" 2 3] ", "
conjoin [1 2 [3]] [pad]
conjoin/only [1 2 [3]] [pad]
conjoin/only [1 2 [3]] 'pad
Anton:
6-Sep-2006
; Anton's enhanced version:
; - /quote is applied to first value, if a string

; - reorders PAD and DATA arguments so PAD is first (being likely 
always short)
; - distinguishes /only and /pad-only
; - renames /quoted -> /quote
conjoin: func [

 "Join the values in a block together with a delimiting PAD value."
	pad "The value to put into the series"
	data [any-block!] "The series to join"
	/only "Inserts a series value in DATA as a series."

 /pad-only "Inserts a series PAD as a series." ; <-- this might not 
 be used much in practice (easy to add extra brackets around PAD)
	/quote "Puts string values in quotes."
	/local ; <- used to track tail of the result as we build it
] [
	if empty? data [return make data 0]

 local: tail either series? local: first data [copy local] [form :local]

 if all [quote any-string? local][local: insert tail insert head local 
 {"} {"}] ; quote the first value
	; <- (local should be at its tail at this point)
	while [not empty? data: next data] either any-string? local [
		either quote [

   [local: insert insert insert insert local pad {"} first data {"}]
		][
			[local: insert insert local pad first data]
		]
	] [
		either only [
			either pad-only [
				[local: insert/only insert/only local pad first data]
			][
				[local: insert/only insert local pad first data]
			]
		][
			either pad-only [
				[local: insert insert/only local pad first data]
			][
				[local: insert insert local pad first data]
			]
		]
	]
	head local
]

; test
conjoin "" []
conjoin "," []
conjoin '| [1 2 [3]]
conjoin '| [[1] 2 [3]]
conjoin ", " [{one} 2 [3]]
conjoin '| [["one"] 2 [3]]
conjoin/only '| [["one"] 2 [3]]

conjoin/only [pad] [1 2 [3]] ; ONLY and PAD-ONLY make no difference 
in string mode
conjoin/only [pad] [[1] 2 [3]]

conjoin/pad-only [pad] [1 2 [3]] ; ONLY and PAD-ONLY make no difference 
in string mode
conjoin/pad-only [pad] [[1] 2 [3]]

conjoin/only/pad-only [pad] [1 2 [3]] ; ONLY and PAD-ONLY make no 
difference in string mode
conjoin/only/pad-only [pad] [[1] 2 [3]]

conjoin/quote "" []
conjoin/quote "," []
conjoin/quote '| [1 2 [3]]
conjoin/quote '| [[1] 2 [3]] ; QUOTE doesn't work in block mode
conjoin/quote ", " [{one} 2 [3]]
conjoin/quote '| [["one"] 2 [3]]
conjoin/quote/only '| [["one"] 2 [3]]

conjoin/quote/only [pad] [1 2 [3]] ; ONLY and PAD-ONLY make no difference 
in string mode
conjoin/quote/only [pad] [[1] 2 [3]]

conjoin/quote/pad-only [pad] [1 2 [3]] ; ONLY and PAD-ONLY make no 
difference in string mode
conjoin/quote/pad-only [pad] [[1] 2 [3]]

conjoin/quote/only/pad-only [pad] [1 2 [3]] ; ONLY and PAD-ONLY make 
no difference in string mode
conjoin/quote/only/pad-only [pad] [[1] 2 [3]]
Anton:
7-Sep-2006
Years ago, I successfully argued to Carl that SWITCH's VALUE argument 
should go before the CASES argument. My reasoning today is the same 
- it is easier to parse visually when the smaller or less frequently 
changing parts of an expression go together. As you can see above, 
all the conjoins with the same PAD argument are easy to see, and 
the more likely to vary DATA blocks begin sometimes at the same horizontal 
position (thus, easier to compare). Just scroll up and compare with 
the tests for your version; look at each line and try to see what 
the differences between them are.

The reasoning that a standard argument order is a good memory guide 
isn't strong enough for me; there is always HELP, and I think the 
particularities of each function are more important when determining 
the order of arguments.
Volker:
7-Sep-2006
BTW i would rething the name for 'decimal! . To me its base-10. float 
or such are better for floats IMHO. If that does not break to much, 
but should be a global replace.
Volker:
7-Sep-2006
Re argument-oder: To me big inline block comes last, vars first. 
Else the standard, the important thing first. With conjoin i am unsure, 
it looks to me as if it rarely has inline-data. If i pad things together, 
i usually have a list, 
  conjoin list-of-things  ","

Its not like 'reduce or 'rejoin, where i mix inline-data with variables, 
which can span some codelines.
If i am wrongand its used like
  cojoin "," ["I" "who writes this" "has more to think about it"]
i am with Anton, small thing first.
Anton:
7-Sep-2006
Yes, overflow either results in an overflow error or a conversion.
Ladislav:
7-Sep-2006
I remember that once there was an issue with a value that MOLD was 
unable to process. Sunanda gave an example of a MONEY! value of this 
kind, but I guess, that there was something else, what was it? - 
a past-tail block/string?
Volker:
7-Sep-2006
Anton, i think that conjion will be used often, but will the argument 
be an inline-block, or a block in a variable? 'rejoin is used as 
an template, 
rejoin["Its" now/time "o'clock"]

In that case the block should be last. 'append is used with block 
in a var, 
'append this-block something

With conjoin i  expect it less like a template and more like 'append.
Anton:
7-Sep-2006
I try to avoid using extra variables. They can be a real pain when 
it comes to optimization and make things look messier. Of course, 
when using a variable the argument order becomes less important. 
It's only important when no variables are used and specified directly.
BrianH:
7-Sep-2006
Looking at your conjoin with the /only and /pad-only refinements, 
it seems that with the /only you are trying to recreate the delimit 
function, but not as usefully. I thought of using pad as a variable 
name, but "delimiter" was more appropriate since padding functions 
usually pad outside the data, not within it. Let me try to add you 
fixes to my version and see what I get.
BrianH:
7-Sep-2006
delimit: func [
    "Put a value between the values in a series."
    data [series!] "The series to delimit"
    delimiter "The value to put into the series"
    /only "Inserts a series delimiter as a series."
    /copy "Change a copy of the series instead."
    /local
] [
    while either copy [
        if empty? data [return make data 0]
        local: make data 2 * length? data
        [
            local: insert/only local first data
            not empty? data: next data
        ]
    ] [
        local: data
        [not empty? local: next local]
    ] pick [
        [local: insert local delimiter]
        [local: insert/only local delimiter]
    ] none? only
    head local
]

conjoin: func [
    "Join the values in a block together with a delimiter."
    data [any-block!] "The series to join"
    delimiter "The value to put into the series"
    /only "Inserts a series delimiter as a series."
    /quoted "Puts string values in quotes."
    /local
] [
    if empty? data [return make data 0]

    local: tail either series? local: first data [copy local] [form :local]
    while [not empty? data: next data] either any-string? local [
        either quoted [
            local: insert tail insert head local {"} {"}

            [local: insert insert insert insert local delimiter {"} first data 
            {"}]
        ] [[local: insert insert local delimiter first data]]
    ] [pick [
        [local: insert insert local delimiter first data]
        [local: insert insert/only local delimiter first data]
    ] none? only]
    head local
]
BrianH:
7-Sep-2006
The pick pattern is also good for nested options, like this

    pick pick [[no-a-no-b no-a-yes-b] [yes-a-no-b yes-a-yes-b]] none? 
    a none? b
BrianH:
7-Sep-2006
If you want to try something really fun, pass a no-argument function 
value as the delimiter argument. You can use this for all sorts of 
tricks, though if you are doing that the references to delimiter 
in the conjoin function should be put in parentheses for safety. 
Like this:
BrianH:
7-Sep-2006
conjoin: func [
    "Join the values in a block together with a delimiter."
    data [any-block!] "The series to join"
    delimiter "The value to put into the series"
    /only "Inserts a series delimiter as a series."
    /quoted "Puts string values in quotes."
    /local
] [
    if empty? data [return make data 0]

    local: tail either series? local: first data [copy local] [form :local]
    while [not empty? data: next data] either any-string? local [
        either quoted [
            local: insert tail insert head local {"} {"}

            [local: insert insert insert insert local (delimiter) {"} first data 
            {"}]
        ] [[local: insert insert local (delimiter) first data]]
    ] [pick [
        [local: insert insert local (delimiter) first data]
        [local: insert insert/only local (delimiter) first data]
    ] none? only]
    head local
]
Volker:
7-Sep-2006
Anton, "I try to avoid using extra variables". In my scenario its 
not an extra variable. I have a block of data from elsewhere, so 
it is in a variable. I want that nicely formed, with delemiters. 
If i want  the data inline, i need no conjoin, i can join it by putting 
all in one string.
Volker:
7-Sep-2006
I have problems to find a case where using it for inline-blocks makes 
much sense. Maybe i have a blackout here, can you give a non-artificial 
case?
Anton:
8-Sep-2006
>> time-it: func [iterations code /local t0 t1][t0: now/precise loop 
iterations code t1: now/precise print difference t1 t0]
>> time-it 4000000 [pick [[a][b]] none? true]
0:00:04.306
>> time-it 4000000 [either true [[a]][[b]]]
0:00:03.555
>> time-it 4000000 [pick [[a][b]] none? none]
0:00:04.266
>> time-it 4000000 [either none [[a]][[b]]]
0:00:03.525
Anton:
8-Sep-2006
... which surprised me a little bit. I think maybe the reason pick 
is favoured in general use is because there's less typing.
Anton:
8-Sep-2006
Brian, I think you might have misunderstood how I reworked the /only 
and /pad-only refinements, or I've misunderstood what you're trying 
to say about it. Let's consider /ONLY:

The first value in DATA is a block, so the result is a block. The 
second value 2 is inserted as is. The third value [3] is a block, 
but the contents are INSERTed, so the block is unwrapped:
	>> conjoin '| [["one"] 2 [3]]
	== ["one" | 2 | 3]


Same result except this time the /ONLY refinement causes the third 
value [3] to be inserted as is, so it remains a block:
	>> conjoin/only '| [["one"] 2 [3]]
	== ["one" | 2 | [3]]


This seems to me to be a necessary option in the treatment of the 
input data.
Anton:
8-Sep-2006
pad

 -> "delimiter"  -  I am forced to agree that "delimiter" is a better 
 word, I'll probably align with you on that, although it's hard to 
 go up to such a longer word again :)
Anton:
8-Sep-2006
No, I have thought of a reasonable situation.
Volker:
8-Sep-2006
So i think its rare and acceptable. While i would use it a lot for 
printing a result-block nicely delemited.
Anton:
8-Sep-2006
Maybe it's hard to think of the usages now, but, you know, it took 
a while to learn when and how to use rejoin.
Oldes:
8-Sep-2006
Just wanted to remind, that Rebcode was here for a short time:-) 
Hope it will come back:-)
BrianH:
9-Sep-2006
As for the word "delimiter" I made sure it wouldn't be exported to 
the external programming environment - no keyword arguments in REBOL, 
and I didn't use it for a function name or refinement. The more precise 
meaning of the word makes it a better choice for source that may 
serve as documentation, using the help or source commands.
Anton:
10-Sep-2006
Yes, please.

I think I lost sight of the overall picture when I added /only and 
/pad-only. (Reminds me of a similar thought process in another frenetic 
function creation a year or two ago (?)) I was not thinking of the 
functionality that DELIMIT covered when I was "designing" those refinements. 
So on further reflection, it looks to me like you are right, for 
CONJOIN, using INSERT rather than INSERT/ONLY on the DATA values 
is more useful.
BrianH:
10-Sep-2006
delimit: func [
    "Put a value between the values in a series."
    data [series!] "The series to delimit"
    delimiter "The value to put into the series"
    /only "Inserts a series delimiter as a series."
    /copy "Change a copy of the series instead."
    /local
] [
    while either copy [
        if empty? data [return make data 0]
        local: make data 2 * length? data
        [
            local: insert/only local first data
            not empty? data: next data
        ]
    ] [
        local: data
        [not empty? local: next local]
    ] either only [
        [local: insert/only local delimiter]
    ] [[local: insert local delimiter]]
    head local
]

conjoin: func [
    "Join the values in a block together with a delimiter."
    data [any-block!] "The values to join"
    delimiter "The value to put in between the above values"
    /only "Inserts a series delimiter as a series."
    /quoted "Puts string values in quotes."
    /local
] [
    if empty? data [return make data 0]

    local: tail either series? local: first data [copy local] [form :local]
    while [not empty? data: next data] either any-string? local [
        either quoted [
            local: insert tail insert head local {"} {"}

            [local: insert insert insert insert local (delimiter) {"} first data 
            {"}]
        ] [[local: insert insert local (delimiter) first data]]
    ] [
        either only [

            [local: insert insert/only local (delimiter) first data]
        ] [[local: insert insert local (delimiter) first data]]
    ]
    head local
]
Tomc:
10-Sep-2006
consider /delimiter  accepting  a block that is rotated through. 
  ["|"  "|" "|" "|^/"]
Anton:
11-Sep-2006
You can do this and anything else when passing in a function as delimiter.
BrianH:
11-Sep-2006
Tom, you can do that by passing a function as the delimiter, like 
this:

    has [x y] [x: ["|"  "|" "|" "|^/"] y: first x if tail? x: next x 
    [x: head x]]
BrianH:
11-Sep-2006
You don't need to parenthesise delimiter in delimit because every 
reference to it is at the end of a block. Using parentheses is slower 
in REBOL, so why use them when you don't have to?
Anton:
12-Sep-2006
d: has [x i][i: [1] i/1: i/1 + 1 pick [a b c] (i/1 - 2 // 3 + 1)]
Anton:
12-Sep-2006
d: has [x][x: [[a b c]] x/1: next either tail? x/1 [head x/1][x/1] 
first back x/1]
Gregg:
12-Sep-2006
Wow. A lot of thought here. I've skimmed it (trying to catch up on 
things quickly), and will just post a couple quick thoughts.


* REJOIN is probably a good enough name to stick with; I don' t know 
that any of the others are that much more meaningful in the context 
of REBOL. 

* Changing JOIN's params would break a lot of code.


* I have a DELIMIT function as well, and like the name. Mine doesn't 
have /copy or /only refinements (it always uses insert/only), but 
it has /skip.
Pekr:
12-Sep-2006
i did not follow the whole discussion, so dunno what exactly 'delimit 
does, but could we have also a 'pad function?
Pekr:
14-Sep-2006
concat came to my mind - because, really guys, for me, czech speaking 
person, conjoin sounds like something rude I even don't know. So 
concat, I at least know as a term from other languages :-)
Volker:
14-Sep-2006
conjoin inserts delemiters too, did i get that right? How about a 
simple 'list, i feel its a good match, listing things. But not native 
speaker.. Another idea: it icould be related to csv (this spreadsheet-format, 
got i the letters right), a conjoin is close to exporting?
Pekr:
14-Sep-2006
we have already list-dir, so list is a good match imo ...
BrianH:
14-Sep-2006
The word "concat" is usually used for a function similar to join 
rejoin.
BrianH:
15-Sep-2006
Well, REBOL blocks can double as datasets, with either nested blocks 
or fixed-length records. You could probably do a variant on conjoin 
that could convert either of these types to a CSV file, even with 
one that has its records delimited by something other than a comma, 
like a tab. Creating a new function to do this based on the techniques 
in conjoin would currently be easier than using conjoin to perform 
this task.
BrianH:
15-Sep-2006
On the other hand, if you don't want a full copy of the CSV fie in 
memory and would rather just convert to disk, conjoin should work 
just fine. It might be a good idea to add a /part option for fixed-length 
record blocks.
Anton:
18-Sep-2006
Ladislav, I'm not sure what the main question is. Could you explain 
the control flow that would lead to a 1 result ?
Volker:
18-Sep-2006
i do not like that a break can break function-nesting.
Ladislav:
18-Sep-2006
i do not like that a break can break function-nesting.

 - you can always "break out of a function", unless the BREAK implementation 
 is faulty
Volker:
18-Sep-2006
I think lexically. if i pass a closure with a break, it should at 
least break into my code, and not inside some foreign code where 
it creates havoc.
Volker:
18-Sep-2006
But we need a way to enforce cleanup? something like 'finally? If 
a module provides an
  open-do-close [my-code]
my code should not be able to avoid the close?
Ladislav:
18-Sep-2006
so in REBOL2 we cannot (at least not in a simple way) use loop when 
implementing a control struct
BrianH:
18-Sep-2006
I would normally be on the side of dynamic break - it would be easier 
to teach, and the rest of REBOL follows that model. What would be 
the major advantage of lexical break in a non-compiled language? 
REBOL code blocks aren't really lexically associated with their control 
structures in the DO dialect, as my conjoin and delimit functions 
above demonstrate. This isn't rebcode you know.
Ladislav:
18-Sep-2006
right. OK, in case we will use dynamic BREAK in REBOL3 (highly probable), 
I will propose to introduce a new /THROW refinement for the WHILE 
cycle to "pass along" BREAK and that is all
Ladislav:
18-Sep-2006
no, because in the case I am programming a control function I do 
not want to force the users to specify the destination just because 
they are using my control function
BrianH:
18-Sep-2006
There are function attributes to prevent a function from catching 
a return or throw, should there be one for break?
Ladislav:
18-Sep-2006
no, because this is a loop business, function attributes cannot help
BrianH:
18-Sep-2006
For that matter, I thought the point to runing a block of code with 
a loop 1 was to catch breaks. Can you rebreak?
Ladislav:
18-Sep-2006
while: native [
    {While a condition block is TRUE, evaluates another block.}
    cond-block [block!]
    body-block [block!]
    /throw {pass along break}
]
Ladislav:
18-Sep-2006
For that matter, I thought the point to runing a block of code with 
a loop 1 was to catch breaks.
 - sorry for my oversimplification, I didn't mean to use *only* 1
Ladislav:
18-Sep-2006
Add it to the other loop functions too.

 - this is a "higher level" business and I will be content with having 
 at least WHILE/THROW. I guess, that it will not be used frequently 
 (?)
Ladislav:
18-Sep-2006
Moreover, it looks to me, that we are able to "simulate" such a construct 
using PARSE in REBOL2
Ladislav:
18-Sep-2006
just a side note: it looks, that we will get CONTINUE in REBOL 3 
too and I suppose the /THROW to "pass along" CONTINUE too
Ladislav:
18-Sep-2006
regarding the structural problem: we should convince Carl to give 
us a comfortable APPLY function, shouldn't we?
Ladislav:
18-Sep-2006
so, I guess that it would be nice if you found a spec for APPLY that 
would be able to handle refinements in some way
BrianH:
18-Sep-2006
I used it quite a bit. You remember how much I posted in the rebcode 
group :)
BrianH:
18-Sep-2006
APPLY would take refinements as positional arguments. That meant 
you would need to match the order of refinements in the declaration 
of the function you are calling, and that your function call would 
break if the function changed the order of its arguments - fragile. 
For some reason APPLY was slow too, and would crash REBOL if run 
too many times in a rebcode function.
Ladislav:
18-Sep-2006
function call would break if the function changed the order of its 
arguments - fragile
 I am afraid, that it is hard to find a less fragile spec, though
BrianH:
18-Sep-2006
Look back on the rebcode group. It was a standing problem. I was 
more concerned about it being slow as dirt though - the instability 
was likely to get fixed, but the slowness may be structural.
BrianH:
18-Sep-2006
Can you get from a refinement to the word it is based on? Are refinements 
bound?
BrianH:
18-Sep-2006
If so, you could pass along the refinements as keyword arguments 
in a REBOL version of APPLY.
BrianH:
18-Sep-2006
Oh well, there goes one idea for a less fragile interface.
Ladislav:
18-Sep-2006
...but if you write f: func [/a] [/a 'a], then the /a refinement 
isn't bound, but the 'a *is*
BrianH:
18-Sep-2006
But if you write
    a: none
    apply :f [/a]

then the apply function can't tell that it should be passing the 
/a refinement as none.
BrianH:
18-Sep-2006
If /a is not bound, I mean.
Ladislav:
18-Sep-2006
right, you would need to write apply :f [/a a]
Gabriele:
21-Sep-2006
hmm, that depends on a lot of things. i'd say yes, but otoh there 
may be cases where that is not a good idea. it's to early to say 
anything about that, anyway.
Maxim:
21-Sep-2006
I agree... and with dual cores becoming increasingly main stream... 
there is a definite advantage in that.
Maxim:
21-Sep-2006
hehe if windows didnt design "kill a task" from inception... I can 
only imagine how well its threads must be implemented.  <sigh>
Gabriele:
21-Sep-2006
there is a crossplatform library iirc, i hope it works :)
BrianH:
21-Sep-2006
Threads are actually done very well on Windows. They also have a 
fast shared-memory thread-like thing called fibers. It was only recently 
that some of the Unixes were able to catch up (except Solaris, which 
may be better).
Anton:
5-Oct-2006
Three letters start to look a little bit cryptic. Reminds me of LISP's 
car, cdr, cadr etc.
Tomc:
5-Oct-2006
yes   get/set  for a   0 based series seems reasonable at the moment
Henrik:
5-Oct-2006
will we need a 'zeroth too?
Volker:
5-Oct-2006
can it be a long name?
  pick-before series 27
is what it does.
Cyphre:
14-Nov-2006
Pekr: The 'old' licence for AGG 2.3 and 2.4 remains. GPL is for 2.5 
which is at the moment at the same leve as 2.4(regarding functionality). 
So far noone from the AGG comunity(or at least at the ML) don't know 
why Maxim decided to change the licence.(everyone is waiting for 
his reply)

Maxim also wrote "Current AGG users who are willing to continue using 
AGG under the old terms and conditions are encouraged to contact 
me and I will consider their requests." so nothing is lost if we 
would like to use 2.5.

Anyway, even the AGG2.3 framework is very stable and have 99% of 
the features same like 2.4 and up. The whole code quality is very 
good so it is possible to enhance it...so this shouldn't be a big 
problem for Rebol.

Another thing is that in the 'worst case' current AGG users/developers 
who don't want or cannot use the GPL version are planning to continue 
with improving the 2.4 codebase separately.
Henrik:
14-Nov-2006
That would shave off a lot of development time for an app, I'm developing. 
Just this one feature. Thanks.
Robert:
17-Nov-2006
I'm always wondering why people depend on the next release to start 
their app... take what you have and do it. There is always a way. 
It's like with a team. You got the people you have and good management 
is, to get to the goal with your team you have. Winning with a dreamteam 
is no art.
Louis:
23-Nov-2006
rebol [
	purpose: "Demonstrate how to use the findany function."
	note:  {This is a function I would like included in Rebol3.
		One of you experts (I don't remember who) made this function 

                for me, and I use it all the time. Do you see any ways it can
		be improved before I submit it? --- Louis
	}
]

s: "findany will return true if it finds in this sentence any of 
the strings you enter in the request box."
print [s newline]

forever [

 bs: copy parse (request-text/title "Enter the strings you want to 
 find separated by a space.") none

	findany: func [ 
	     "Searches string x for any substring found in block ys."
	     x [string!] "string"
	     ys [block!] "block of substrings"
	    /local pos
	] [
	    foreach y ys [
	         if pos: find x y [return pos]
	     ]
	]

either findany s bs [print true][print false]

]
halt
Louis:
23-Nov-2006
rebol [
	purpose: "Demonstrate how to use the findall function."
	note:  {This is a function I would like included in Rebol3.
		This is my function. Do you see any ways it can
		be improved before I submit it? --- Louis}
]

s: "findall will return true only if it finds in this sentence all 
the strings you enter in the request box."
print [s newline]

forever [

 bs: copy parse (request-text/title "Enter the strings you want to 
 find separated by a space.") none

	findall: func [
		"Seaches string s for all substrings find in block bs."
		s [string!] "string to search in"
		bs [block!] "block of strings to search for"
	][
		findit: func [
			s [string!] "string to search in"
		        b [string!] "string to search for" 
		][
			if find s b [either find s b [true][false]]
		]
		foreach b bs [either findit s b [true][break/return false]]
	]

either findall s bs [print true][print false]

]
halt
Anton:
24-Nov-2006
Functions like these are very useful to have. I could have used them 
recently while doing file searching.
However, I wouldn't like to see these functions included as is.

- Not very efficient. That's ok  for searching small strings or the 
contents of short files, but bad when searching large files for many 
strings. 

- Not generic. The name suggests many datatypes are supported. Better 
names might be find-any-string, find-all-strings
- The above FINDALL does not keep FINDIT as a local.

- The argument names are too short, so they are not distinct or descriptive 
enough.

- The return values are not defined clearly in the function doc strings. 
The above issues are fixable, but it will take some time.
Louis:
24-Nov-2006
Who can make these functions the most efficient, and display them 
in a benchmark program to prove it? And correct all the other problems 
mentioned by Anton.
[unknown: 5]:
24-Nov-2006
Louis, the way I benchmark in REBOL is to do a trace count.  In other 
words if the execution of the trace generates more output than another 
method then I assume that method is less efficient.
Anton:
25-Nov-2006
Stayed up all night, and succeeded in making a parse rule generator, 
so if we want to search a string for any substrings:

string: {Hello there Anton. Arrow in the box. What nice antlers you 
have.}
substrings: ["ant" "antler" "anton" "arrow" "bar" "box"]

rule: [start: [["a" [["nt" action ["ler" action | "on" action]] | 
"rrow" action]] | ["b" ["ar" action | "ox" action]]] | skip]
Found at: 13 Substring: "Ant"
Found at: 13 Substring: "Anton"
Found at: 20 Substring: "Arrow"
Found at: 33 Substring: "box"
Found at: 48 Substring: "ant"
Found at: 48 Substring: "antler"
true
Anton:
25-Nov-2006
Thus we are able to search large files for any number of substrings 
in a single pass parse. :)
Anton:
25-Nov-2006
Thankyou, Jerry. I wonder if anyone else made a parse generator like 
that ?
Louis:
25-Nov-2006
Maxim and Anton, what difference does it make which value is returned? 
It is the true or false that I am looking for. If any of the strings 
are found, why look any farther? I'm sure you guys have a reason, 
but I want to know what it is.
Anton:
25-Nov-2006
.. and a name like FINDALL suggests that it returns those matches.
Louis:
25-Nov-2006
But I would really like to see funtions that find-any-substring and 
that find-all-substrings included in REBOL3, as they make programming 
a lot easier---at least for me.
26801 / 6460812345...267268[269] 270271...643644645646647