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

[REBOL] Re: Multi-searches

From: joel:neely:fedex at: 20-Feb-2002 20:31

Hi, Jason, Jason Cunliffe wrote:
> That's interesting. Could you expand a little please.. > What do you mean by "non-fall-through exit" ? >
A "fall-through" exit is one that "falls" out of the end of the function. A non-fall-through exit terminates the function evaluation prior to reaching the end of the normal sequential flow. RETURN essentially acts as "go to the out door". Here's a strict one-way-out function to compute the real roots of a quadratic equation. If the discriminant is... ...there are _ real roots. ------------------------- -------------------------- negative no zero two equal positive two distinct 8<------------------------------------------------------------ quadform1: func [a [number!] b [number!] c [number!] /local d] [ d: b * b - (4.0 * a * c) either d < 0 [ [] ][ a: 1.0 / 2.0 / a b: - b either d = 0 [ reduce [b * a] ][ d: square-root d reduce [b + d * a b - d * a] ] ] ] 8<------------------------------------------------------------ Notice that this "purist" version uses nested conditions to evaluate only the appropriate expressions. In contrast: 8<------------------------------------------------------------ quadform2: func [a [number!] b [number!] c [number!] /local d] [ d: b * b - (4.0 * a * c) if d < 0 [return []] a: 1.0 / 2.0 / a b: - b if d = 0 [return reduce [b * a]] d: square-root d reduce [b + d * a b - d * a] ] 8<------------------------------------------------------------ the above version uses "early exits" via RETURN to bail out as soon as the result is determined. YMMV but some folks think that the second version is easier to read because of the absence of nesting. Of course these two are equivalent mod a trivial syntactic rewrite. Sometimes early exits make a significant difference in structure or performance. Consider a function that tests whether all numbers in a block are even: 8<------------------------------------------------------------ alleven1: func [blk [block!] /local evensofar] [ evensofar: true foreach nbr blk [ evensofar: evensofar and even? nbr ] evensofar ] 8<------------------------------------------------------------ That one is certainly correct, but may work more than necessary (since FALSE is a zero for AND). It can be written (at a cost of performance) to make explicit tests of both the state of the block and the state of the accumulator variable: 8<------------------------------------------------------------ alleven2: func [blk [block!] /local evensofar] [ evensofar: true while [all [not empty? blk evensofar]] [ evensofar: even? first blk blk: next blk ] evensofar ] 8<------------------------------------------------------------ ...but that's just clunky-looking. Both of those functions used fall-through exits, because they were structured to flow all the way to the end. If we take off our purist hats and take advantage of RETURN, we can write this as: 8<------------------------------------------------------------ alleven3: func [blk [block!]] [ foreach nbr blk [ if odd? nbr [return false] ] true ] 8<------------------------------------------------------------ The RETURN is necessary *inside* the loop to force early departure from the function. At the end, we only need to provide the (trivial) expression for the result. 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" ;