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

for bug?

 [1/23] from: rotenca:telvia:it at: 16-Jun-2002 20:41


In a console for x #"^(00)" #"^(ff)" 1 [print to integer! x] -> endless loop A bug or something i do not understand? --- Ciao Romano

 [2/23] from: joel:neely:fedex at: 16-Jun-2002 16:42


Hi, Romano, It has to do with (non-intuitive IMHO) handling of arithmetic on character values... Romano Paolo Tenca wrote:
> In a console > > for x #"^(00)" #"^(ff)" 1 [print to integer! x] > > -> endless loop >
No matter how many times you add 1 to a character value, it will never be greater than #"^(ff)" (believe it or not!)
>> foo: #"^(ff)"
== #""
>> foo + 1
== #"^@"
>> to-integer foo + 1
== 0 You might have been expecting that
>> (to-integer foo) + 1
== 256 would cause the loop to exit once the counter had exceeded the stated upper bound, but...
>> to-char (to-integer foo) + 1
** Math Error: Math or number overflow ** Where: to-char ** Near: to char! :value On the other hand, for x to-integer #"^(00)" to-integer #"^(ff)" 1 [print x] works just fine, and you can use the phrase to-char x inside the body of the FOR if you really wanted to do something with all possible character values. -jn- -- ; Joel Neely joeldotneelyatfedexdotcom 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 ]

 [3/23] from: g:santilli:tiscalinet:it at: 17-Jun-2002 0:44


Hi Romano, On Sunday, June 16, 2002, 8:41:22 PM, you wrote: RPT> A bug or something i do not understand?
>> #"^(ff)" + 1
== #"^@" Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [4/23] from: rotenca:telvia:it at: 17-Jun-2002 8:11


Hi Joel and Gabriele, thanks for your answers. My point of view is that if 'for accepts unsigned integer, it must know how to handle them. In my expression i have asked to stop at 255 not at something > 255. I think that 'for should be an until loop: until [ ... i >= 255 ] not a while loop: while [i > 255][ ... ] else 'for couldn't handle unsigned value in the right mode and it should not accept values it does not know how to handle. But perhaps others languages have this limitation in their for loop with unsigned values. Joel do you confirm this? --- Ciao Romano

 [5/23] from: joel:neely:fedex at: 17-Jun-2002 7:44


Hi, Romano, Romano Paolo Tenca wrote:
> My point of view is that if 'for accepts unsigned integer, > it must know how to handle them.
<<quoted lines omitted: 6>>
> not a while loop: > while [i > 255][
i <= 255 ;; just a typo
> ... > ] > > else 'for couldn't handle unsigned value in the right mode > and it should not accept values it does not know how to handle. >
The problem with post-condition tests is their inability to do nothing gracefully . In the case
>> for i 3 2 1 [print i]
== none which can be understood as print each number i in the range [3 <= i <= 2] stepping by 1 nothing should print, because the range is empty.
> But perhaps others languages have this limitation in their for > loop with unsigned values. Joel do you confirm this? >
The issue is not unsigned values, but rather what happens at the edge of a finite domain (and, with programming, all elementary domains are finite... ;-) Consider the following:
>> for i 2147483640 2147483647 1 [print i]
2147483640 2147483641 2147483642 2147483643 2147483644 2147483645 2147483646 2147483647 ** Math Error: Math or number overflow ** Where: for ** Near: start: start + bump versus
>> a: #"^(fa)"
== #""
>> loop 6 [print mold a: a + 1]
#"" #"" #"" #"" #"" #"^@" versus
>> a: 255.255.255.250
== 255.255.255.250
>> loop 6 [print a: a + 1]
255.255.255.251 255.255.255.252 255.255.255.253 255.255.255.254 255.255.255.255 255.255.255.255 So, REBOL handles hitting the limit of a domain in at least three distinct ways, depending on type: 1) throwing an error integer! 2) wrapping within domain char! 3) "sticking" at the limit tuple! Anyone know of any others? IMHO any effort to redefine the behavior of FOR should address the following issues: - REBOL's use of strongly-typed values (e.g. (#"^(ff)" + 1) evaluates to char! rather than widening to integral 256) - the ability to do nothing gracefully - the handling of limit values - minimizing overhead (maximizing performance) I don't have a good answer at this point, but we are talking about a limited number of special cases where this happens (max values for the types {number series money time date char}). -jn- -- ; Joel Neely joeldotneelyatfedexdotcom 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 ]

 [6/23] from: joel:neely:fedex at: 17-Jun-2002 8:49


Hi, again, Romano and list, Joel Neely wrote:
> Romano Paolo Tenca wrote: > >
<<quoted lines omitted: 11>>
> print each number i in the range [3 <= i <= 2] stepping by 1 > nothing should print, because the range is empty.
...
> IMHO any effort to redefine the behavior of FOR should address > the following issues: >
...
> - minimizing overhead (maximizing performance) >
It is interesting that replacing while [op end start] [ start: start + bump ] with if op end start [ until [ start: (old: start) + bump ] ] would actually appear to improve performance, as well as addressing Romano's issue with #"^(ff)" as an upper loop bound. -jn-

 [7/23] from: rotenca:telvia:it at: 17-Jun-2002 16:19


Hi Joel,
> 1) throwing an error integer! > 2) wrapping within domain char! > 3) "sticking" at the limit tuple! > > Anyone know of any others?
I have found a sort of signed integer which wraps (but in a strange mode): x: to time! 2147483646 loop 5 [print x: x + 1] 596523:14:07 --596523:-14:-08 ; ? -596523:14:07 -596523:14:06 -596523:14:05 --- Ciao Romano

 [8/23] from: rotenca:telvia:it at: 17-Jun-2002 16:47


Hi Joel,
> The problem with post-condition tests is their inability to > "do nothing gracefully". In the case
<<quoted lines omitted: 3>>
> print each number i in the range [3 <= i <= 2] stepping by 1 > nothing should print, because the range is empty.
It seems to me that the solution is a pre-conditon test and a post-condition test with something like: myfor: func ['word start end bump body /local i do-body][ do-body: func reduce [[throw] word] body i: start while [i <= end] [ do-body i if i >= end [break] i: i + bump ] ] This slows code a little, i admit.
> Consider the following: > >> for i 2147483640 2147483647 1 [print i]
<<quoted lines omitted: 9>>
> ** Where: for > ** Near: start: start + bump
I think that an overflow error! is the right thing to do also with unsigned byte (char). Because this is exactly what is happening with a char in 'for: it can't add 1 to 255 without overflow. I agree: the problem is also how Rebol handles limit values. Orthogonality is low. --- Ciao Romano

 [9/23] from: rotenca:telvia:it at: 17-Jun-2002 17:26


To end: another signed integer which wraps: x: 2147483646x2147483646 loop 5 [print x: x + 1] 2147483647x2147483647 -2147483648x-2147483648 -2147483647x-2147483647 Joel, i do not understand your for code, is missing something? if op end start [ until [ start: (old: start) + bump ] ] --- Ciao Romano

 [10/23] from: joel:neely:fedex at: 17-Jun-2002 11:36


Hi, Romano, On Monday, June 17, 2002, at 10:26 AM, Romano Paolo Tenca wrote:
> Joel, i do not understand your for code, is missing something? > > if op end start [ > until [ > start: (old: start) + bump > ] > ] >
What's missing is the working part of the loop body. I stripped the loop down to just the "counter" management to see what would happen to the overhead timing in going to post-test. I think that a single range test wrapped around the post-test loop is much faster than putting another upper-limit test inside a pre-test loop. -jn-

 [11/23] from: joel:neely:fedex at: 17-Jun-2002 12:36


Just a bit more detail... (I'm multitasking furiously this week ;-) On Monday, June 17, 2002, at 11:36 AM, Joel Neely wrote:
> Hi, Romano, > On Monday, June 17, 2002, at 10:26 AM, Romano Paolo Tenca wrote:
<<quoted lines omitted: 19>>
> [rebol-request--rebol--com] with "unsubscribe" in the subject, without the > quotes.
Using the following dinky timing function: race: func [end [number!] /local op start bump old t0 t1 t2][ op: :greater-or-equal? bump: 1 start: 1 t0: now/time/precise while [op end start] [start: start + bump] t1: now/time/precise - t0 start: 1 t0: now/time/precise until [ start: (old: start) + bump op old end ] t2: now/time/precise - t0 print [t1 t2] ] which implements the pre- and post-test loops with no actual processing inside the body, I get
>> race 5000000
0:00:30.222434 0:00:25.854029 which shows that we could pick up about an 11% performance improvement by having UNTIL rather than WHILE as the working part of FOR as Romano has suggested. (Notice that I didn't bother to wrap UNTIL in the IF pre-test since that's a one-shot cost.) -jn-

 [12/23] from: joel:neely:fedex at: 17-Jun-2002 13:51


Hi, again, On Monday, June 17, 2002, at 09:47 AM, Romano Paolo Tenca wrote:
> It seems to me that the solution is a pre-conditon test and a > post-condition
<<quoted lines omitted: 7>>
> Orthogonality is > low.
For a peek at a different (very clean) strategy to handling loops, I might suggest a peek at the "iterator" concept in Python 2.2 described at http://www.amk.ca/python/2.2/ In brief, when you write something resembling (I'll use REBOL-ish notation rather than trying to explain Python syntax): foreachin gleep bletch [...] the variable GLEEP would iterate across all values offered by the object BLETCH. The mechanism, however, is seriously cool and scalable. The object BLETCH merely has to meet two requirements: - there must be a /NEXT refinement which is invoked for every pass to obtain the next element to use, - invoking BLETCH/NEXT must result in a StopIteration exception when there is no next element. Since FOREACHIN is simply looking for the StopIteration exception as the signal for "there are no more values", an object can do whatever makes sense to offer up the next value (or signal completion). This allows the programmer to create new objects and still use them with the standard iterative loop mechanism with no extra overhead. Since RANGE (remember that I'm still using REBOL notation) returns a range object which already has the required behaviors, and "file" objects also know how to behave, one uses foreachin foo range 1 100 [...] or foreachin line %glumpf.data [...] to do just what you think. Anyway, the idea of having a standard interface that allows extensions (or type-specific scenarios, such as we've been discussing with char!) to work consistently with looping seems quite nice. -jn-

 [13/23] from: rotenca:telvia:it at: 17-Jun-2002 22:47


Hi Joel, some notes about this thread (also to clear my looping mind :-): 1) it is strange, but your simulation code is more slow on my system (W98 - Celeron 333 view 1.2.1.3.1 and beta 1.2.5.3.1) than the standard simulated 'for
>>race 500000
0:00:03.52 0:00:04.01 2) neither your code can check this case: for i #"^(00)" #"^(01)" 256 [] the code should do an additional test of this type (with positive bump): if old => old + bump [break] 3) the right solution should be a consistent math overflow error with all scalar datatype! and not a pseudo-random [error wrap stop bug] like it is in the actual implementation (bug is for the time! datatype!) :-) 4) I always think that for i #"^(00)" #"^(ff)" 1 [] should stop at #"^(ff)", with or without math overflow and with or without wrap, so 'for should check the end condition at the end of the loop and before adding the bump value. 5) a while or until loop is the best mode to do what 'for should do, so one can directly control what happens (and a rebol for loop is always slower than a rebol while/until loop) --- Ciao Romano

 [14/23] from: g:santilli:tiscalinet:it at: 17-Jun-2002 23:49


Hi Joel, On Monday, June 17, 2002, 8:51:19 PM, you wrote: JN> - there must be a /NEXT refinement which is invoked for every pass to JN> obtain JN> the next element to use, JN> - invoking BLETCH/NEXT must result in a StopIteration exception when JN> there is JN> no next element. Hmm, should be trivial to do in REBOL. I'll do that later, it will be fun. :) Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [15/23] from: joel:neely:fedex at: 18-Jun-2002 7:28


Hi, Romano, Romano Paolo Tenca wrote:
> 1) it is strange, but your simulation code is more slow on my > system (W98 - Celeron 333 view 1.2.1.3.1 and beta 1.2.5.3.1) > than the standard simulated 'for > > >>race 500000 > > 0:00:03.52 0:00:04.01 >
May I suggest - increasing the argument at least one order of magnitude - running multiple times I've seen situations where some transient condition could easily throw a half-second glitch into a small benchmark. The first run I made of (an earlier version of) RACE the result favored the WHILE version over the UNTIL version, but over a large number of subsequent runs with larger loop counts the UNTIL version was the consistent winner.
> 2) neither your code can check this case: > > for i #"^(00)" #"^(01)" 256 [] >
You're right. Ooops.
> 3) the right solution should be a consistent math overflow error > with all scalar datatype! and not a
<<quoted lines omitted: 4>>
> for i #"^(00)" #"^(ff)" 1 [] > should stop at #"^(ff)", with or without math overflow and with
I assume you mean "after" instead of "at", that is the #"^(ff)" should be processed but should be the last value to be processed.
> or without wrap, so 'for should check the end condition at the > end of the loop and before adding the bump value. >
I'm beginning to think that the optimal solution to all of the above would be something like the following: 1) perform type consistency checks and throw an error if bounds and increment are not suitable 2) calculate the number of values that actually satisfy both the bounds/increment constraints and the domain constraints of the bounds types 3) if the number of such values is zero, the range is empty, so do nothing gracefully and exit 4) if the number of such value is non-zero, set CURRENT to the lower bound, then... 5) use LOOP (controlled by the number of values calculated in step 2) to perform the body and then increment CURRENT by the supplied "bump" argument. This strategy would push all of the boundary issues into step 2, eliminating the attempted evaluation of an out-of-bounds value within the loop, no matter what the types of the data, nor the handling of edge effects by REBOL. The added overhead would go into loop setup rather than loop body and the iteration would actually be performed by LOOP, so for sufficiently large iteration counts, there should be a net gain of performance. -jn- -- ; Joel Neely joeldotneelyatfedexdotcom 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 ]

 [16/23] from: lmecir:mbox:vol:cz at: 18-Jun-2002 18:22


I think, that FOR contains quite a few other bugs too and its speed is poor. My observations are: too aggressive CATCH attribute handling and incorrect series handling -L

 [17/23] from: g:santilli:tiscalinet:it at: 18-Jun-2002 19:37


Hi Joel, On Monday, June 17, 2002, 8:51:19 PM, you wrote: JN> foreachin gleep bletch [...] My QAD solution: foreachin: func ['word object body /local result] [ if none? object [return none] body: func reduce [word] body if not all [in object 'next in object 'current] [make error! "Invalid object"] until [ set/any 'result body object/current object/next ] get/any 'result ] range: func [start end' bump'] [ if end' - start / bump' < 1 [return none] context [ current: start end: end' bump: bump' op?: either positive? bump [:greater?] [:lesser?] next: does [ current: current + bump op? current end ] ] ]
>> foreachin i range 1 10 1 [print i]
1 2 3 4 5 6 7 8 9 10
>> foreachin i range 10 1 -1 [print i]
10 9 8 7 6 5 4 3 2 1 Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [18/23] from: g:santilli:tiscalinet:it at: 18-Jun-2002 18:33


Hi Joel, On Tuesday, June 18, 2002, 2:28:42 PM, you wrote: JN> 1) perform type consistency checks and throw an error if bounds JN> and increment are not suitable JN> 2) calculate the number of values that actually satisfy both the JN> bounds/increment constraints and the domain constraints of JN> the bounds types JN> 3) if the number of such values is zero, the range is empty, so JN> do nothing gracefully and exit JN> 4) if the number of such value is non-zero, set CURRENT to the JN> lower bound, then... JN> 5) use LOOP (controlled by the number of values calculated in JN> step 2) to perform the body and then increment CURRENT by the JN> supplied "bump" argument. Interesting idea... something like: for: func [ "Repeats a block over a range of values." [catch throw] 'word [word!] "Variable to hold current value" start [number! series! money! time! date! char!] "Starting value" end [number! series! money! time! date! char!] "Ending value" bump [number! money! time! char!] "Amount to skip each time" body [block!] "Block to evaluate" /local result do-body times ][ if (type? start) <> (type? end) [ throw make error! reduce ['script 'expect-arg 'for 'end type? start] ] do-body: func reduce [[throw] word] body op: :greater-or-equal? either series? start [ if not same? head start head end [ throw make error! reduce ['script 'invalid-arg end] ] times: 1 + to-integer divide subtract index? end index? start bump loop times [ set/any 'result do-body start start: skip start bump ] ] [ times: 1 + to-integer divide subtract end start bump loop times [ set/any 'result do-body start start: start + bump ] ] get/any 'result ] Do you see any problems with it? Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [19/23] from: joel:neely:fedex at: 18-Jun-2002 23:12


Hi, Gabriele, Gabriele Santilli wrote:
> Hi Joel, > > On Monday, June 17, 2002, 8:51:19 PM, you wrote: > > JN> foreachin gleep bletch [...] > > My QAD solution: > > foreachin: func ['word object body /local result] [ > if none? object [return none]
... until [ set/any 'result body object/current object/next ] get/any 'result
> ] > > range: func [start end' bump'] [ > if end' - start / bump' < 1 [return none] > context [
...
> ] > ] >
That's a nice first cut, but it assumes that the object passed to FOREACHIN will be able to deliver at least one value (since the UNTIL loop doesn't check for failure until after trying to evaluate the body on CURRENT. I realize that you handled that for RANGE objects, but the thing that's nice about the iterator-driven loop in Python is that ANY object (including one with mutable state/content) can expose the correct interface to allow FOREACHIN to operate on it (including the "do nothing gracefully" case). It's too late for me to play any more with this tonight, but there are two approaches that immediately come to mind around this issue: 1) Inside FOREACHIN simply repeatedly apply the body to /NEXT until /NEXT throws an error. If the error contains a "Stop Iteration" message, simply return RESULT's value as the value of FOREACHIN; if the error is any other kind, then pass it on. 2) Require the object to have two methods /MORE? and /NEXT where /MORE? indicates whether it is possible to call /NEXT without failure, and /NEXT returns the next unused value from the iterator. Sketching out an example for (2), we could then imagine foreachin temp series-iterator some-series [...] where (DANGER, WILL ROBINSON: UNTESTED CODE AHEAD!) series-iterator: func [s [series!]] [ make object! [ ser: s more?: func [] [empty? ser] next: func [/local result] [ result: first ser ser: next ser result ] ] ] as an example of something that could do nothing gracefully. -jn- -- ; Joel Neely joeldotneelyatfedexdotcom 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 ]

 [20/23] from: joel:neely:fedex at: 18-Jun-2002 22:49


Hi, Gabriele, Gabriele Santilli wrote:
> Interesting idea... something like: > > for: func [
...
> ][
...
> ] > > Do you see any problems with it? >
There's good news and bad news: 1) A QAD test indicates a big performance win. After renaming your posted version to NEWFOR, I ran the following (wrapped for the email): t0: now/time/precise for i 1 10000000 1 [] t1: now/time/precise - t0 and got == 0:01:14.557616 than ran: t0: now/time/precise newfor i 1 10000000 1 [] t1: now/time/precise - t0 and got == 0:00:59.648256 which shows about a 20% reduction in run time. 2) This does, indeed, solve Romano's problem with using FOR to iterate through char! values, as shown by: n: 0 newfor i #"^(00)" #"^(ff)" 51 [ n: n + 1 print [n tab to-integer i] if n > 10 [break] ] which gives: 1 0 2 51 3 102 4 153 5 204 6 255 == none versus: n: 0 for i #"^(00)" #"^(ff)" 51 [ n: n + 1 print [n tab to-integer i] if n > 10 [break] ] which exhibits Romano's Syndrome: 1 0 2 51 3 102 4 153 5 204 6 255 7 50 8 101 9 152 10 203 11 254 == none (Of course the business with N was to compensate for my slow reaction time on the "Escape" key! ;-) 3) I believe that (with a bit more work) NEWFOR could be extended to handle tuple! ranges as well. Being able to iterate thru a collection of IP addresses or skip through color space seems to be useful. On the other hand... 1) Integer ranges wider than the maximum integral value break the computation of iteration count; with the existing FOR: for i -2147483647 1147483647 1000000000 [print i] we get behavior as expected: -2147483647 -1147483647 -147483647 852516353 while with the new version: newfor i -2147483647 1147483647 1000000000 [print i] we get a new breakage mode: ** Math Error: Math or number overflow ** Where: newfor ** Near: times: 1 + to-integer divide I had planned on adding a later note that the iteration count computation would need to be performed in decimal! (with suitable protection against round-off error contaminating the iteration count), due to just this issue, but I had a class that kept me to busy to remember that follow-up. 2) There's a bit more work needed in loop unrolling to prevent edge-of-domain failure:
>> newfor i 2147483637 2147483647 2 [print i]
2147483637 2147483639 2147483641 2147483643 2147483645 2147483647 ** Math Error: Math or number overflow ** Where: newfor ** Near: start: start + bump something along the lines of replacing times: 1 + to-integer divide subtract end start bump loop times [ set/any 'result do-body start start: start + bump ] with if 0 < times: i + to-integer (end - start) / bump [ set/any 'result do-body start loop times - 1 [ start: start + bump set/any 'result do-body start ] ] seemed to do the trick:
>> newfor i 2147483637 2147483647 2 [print i]
2147483637 2147483639 2147483641 2147483643 2147483645 2147483647 3) The "bit more work" to address tuple! values would have to deal with calculating the "width" of a range of tuple values, and the peculiar behavior of tuple arithmetic (perhaps to correct it, at least for the purpose of NEWFOR!)
>> baseIP: 255.0.0.0
== 255.0.0.0
>> loop 20 [print baseIP: baseIP + 0.10.20.30]
255.10.20.30 255.20.40.60 255.30.60.90 255.40.80.120 255.50.100.150 255.60.120.180 255.70.140.210 255.80.160.240 255.90.180.255 255.100.200.255 255.110.220.255 255.120.240.255 255.130.255.255 255.140.255.255 255.150.255.255 255.160.255.255 255.170.255.255 255.180.255.255 255.190.255.255 255.200.255.255 However, I think that's a very manageable task. Thanks for the amazingly quick post! -jn- -- ; Joel Neely joeldotneelyatfedexdotcom 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 ]

 [21/23] from: g:santilli:tiscalinet:it at: 19-Jun-2002 12:34


Hi Joel, On Wednesday, June 19, 2002, 5:49:56 AM, you wrote: JN> 1) Integer ranges wider than the maximum integral value break JN> the computation of iteration count; with the existing FOR: LOOP only accepts integers... OTOH we could nest two LOOPs to have 64bit wide integer ranges. :) JN> 2) There's a bit more work needed in loop unrolling to prevent JN> edge-of-domain failure: Maybe we could add just some error handling... JN> 3) The "bit more work" to address tuple! values would have to JN> deal with calculating the "width" of a range of tuple values, JN> and the peculiar behavior of tuple arithmetic (perhaps to JN> correct it, at least for the purpose of NEWFOR!) I'll leave that to the reader as a useful exercise. ;-) JN> Thanks for the amazingly quick post! It was easy to do... :) Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [22/23] from: g:santilli:tiscalinet:it at: 19-Jun-2002 12:38


Hi Joel, On Wednesday, June 19, 2002, 6:12:17 AM, you wrote: JN> That's a nice first cut, but it assumes that the object passed JN> to FOREACHIN will be able to deliver at least one value (since JN> the UNTIL loop doesn't check for failure until after trying to JN> evaluate the body on CURRENT. Indeed. My first version was using THROW on /NEXT, but I realized it was probably uselessly complicated, as the issue with "no iteration at all" can be dealt differently. JN> 2) Require the object to have two methods /MORE? and /NEXT JN> where /MORE? indicates whether it is possible to call /NEXT JN> without failure, and /NEXT returns the next unused value JN> from the iterator. I have a third: let the first /NEXT be no-op, and return immediately true if there's nothing to do. Anyway, your seems the simplest. Regards, Gabriele. -- Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r

 [23/23] from: joel:neely:fedex at: 19-Jun-2002 10:49


Hi, Gabriele, I had the compression ratio set too high... Sorry! On Wednesday, June 19, 2002, at 05:34 AM, Gabriele Santilli wrote:
> Hi Joel, > > On Wednesday, June 19, 2002, 5:49:56 AM, you wrote: > > JN> 1) Integer ranges wider than the maximum integral value break > JN> the computation of iteration count; with the existing FOR: > > LOOP only accepts integers... OTOH we could nest two LOOPs to have > 64bit wide integer ranges. :)
What I was thinking about was a range with widely-spaced endpoints (wider than maxint), but also with a large step value, so that the actual number of loop cycles would be integral, but the intermediate calculation would break, as in newfor i -2147483647 1147483647 1000000000 [print i] ** Math Error: Math or number overflow ** Where: newfor ** Near: times: 1 + to-integer divide Given the desire to get the performance and behavioral improvements, I've only been able to come up with a "mixed" strategy (something like FOR already does for series vs. range iterations) as follows: - if the number of values in the range is within maxint, then set up for using LOOP to manage the work, - if the number of values in range exceeds maxint, but there are no boundary problems to address, use a simple WHILE (similar to current FOR), - if the number of values in range exceeds maxint, and there *are* some boundary problems to address, use a WHILE with additional error handling for bailout. I'll play "reader" when I get the chance. ;-) -jn-

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