How to exit loops?

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

How to exit loops?

ZuLuuuuuu
Hello,

Is there a way to exit loops if a condition is met? For example:

1 to: 10 do: [:x |
        x = 3 ifTrue: [
                ...
        ]
]

What should I write instead of three dots to exit the loop if x is equal to 3?



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Canol Gökel
Reply | Threaded
Open this post in threaded view
|

Re: How to exit loops?

Nicolas Cellier-3
Canol Gokel wrote:

> Hello,
>
> Is there a way to exit loops if a condition is met? For example:
>
> 1 to: 10 do: [:x |
> x = 3 ifTrue: [
> ...
> ]
> ]
>
> What should I write instead of three dots to exit the loop if x is equal to 3?


Usual ways to do it:

1) put a return instruction in the ifTrue: block
However, the interpreter will exit the current method and not execute
instructions after the to:do:...

2) use some kinf of detect:ifNone: trick
(1 to: 10) detect: [:x | x = 3 or: [... false.]] ifNone: [].


Unusual way:

3) do it with an Exception.
Create a new Exception subclass, say ExitLoop.
Then write:

[1 to: 10 do: [:x | x = 3 ifTrue: [ExitLoop raise] ...]]
        on: ExitLoop do: [:exc | exc return: nil].


Nicolas



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: How to exit loops?

Nicolas Cellier-3
nice wrote:

> Canol Gokel wrote:
>> Hello,
>>
>> Is there a way to exit loops if a condition is met? For example:
>>
>> 1 to: 10 do: [:x |
>>     x = 3 ifTrue: [
>>         ...
>>     ]
>> ]
>>
>> What should I write instead of three dots to exit the loop if x is
>> equal to 3?
>
>
> Usual ways to do it:
>
> 1) put a return instruction in the ifTrue: block
> However, the interpreter will exit the current method and not execute
> instructions after the to:do:...
>
> 2) use some kinf of detect:ifNone: trick
> (1 to: 10) detect: [:x | x = 3 or: [... false.]] ifNone: [].
>
>
> Unusual way:
>
> 3) do it with an Exception.
> Create a new Exception subclass, say ExitLoop.
> Then write:
>
> [1 to: 10 do: [:x | x = 3 ifTrue: [ExitLoop raise] ...]]
>     on: ExitLoop do: [:exc | exc return: nil].
>
>
> Nicolas

Forgot a usual fourth way:

4) use a Stream.

exit := false.
stream := (1 to: 10) readStream.
[ exitLoop or: [stream atEnd]]
        whileFalse: [| x |
                x := stream next.
                x = 3
                        ifTrue: [exit := true]
                        ifFalse: [...]].



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Re: How to exit loops?

Lukas Renggli
My preferred way is the following:

Add the following method to Object (or somewhere else):

Object>>escaper: aBlock
   ^ aBlock value: [ ^ nil ]

Then implement your loop like this:

self escaper: [ :break |
   1 to: 10 do: [ :x |
      x = 3 ifTrue: [ break value ].
      ... ] ]

Cheers,
Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: How to exit loops?

Nicolas Cellier-3
Lukas Renggli a écrit :

> My preferred way is the following:
>
> Add the following method to Object (or somewhere else):
>
> Object>>escaper: aBlock
>    ^ aBlock value: [ ^ nil ]
>
> Then implement your loop like this:
>
> self escaper: [ :break |
>    1 to: 10 do: [ :x |
>       x = 3 ifTrue: [ break value ].
>       ... ] ]
>
> Cheers,
> Lukas
>

Very Smaltalk-ish!

Even works if you want to escape nested loop:

self escaper: [:breakOuter |
    1 to: 10 do: [:i |
       self escaper: [:breakInner |
          1 to: 10 do: [:j |
             j = 3 ifTrue: [breakInner value].
             (j = 2 and: [i = 7]) ifTrue: [breakOuter value]]]]].

Nicolas



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: How to exit loops?

ZuLuuuuuu
nicolas cellier <ncellier <at> ifrance.com> writes:

>
> Very Smaltalk-ish!
>
> Even works if you want to escape nested loop:
>
> self escaper: [:breakOuter |
>     1 to: 10 do: [:i |
>        self escaper: [:breakInner |
>           1 to: 10 do: [:j |
>              j = 3 ifTrue: [breakInner value].
>              (j = 2 and: [i = 7]) ifTrue: [breakOuter value]]]]].
>
> Nicolas
>


Thank you for your answers, I also found a solution by extending the Number
class like this:



Number extend [
        to: stop do: aBlock butPleaseExitIf: aCondition [

        <category: 'shortcuts and iterators'>
        | i |
        i := self.
        [(i <= stop) and: [(aCondition value: i) not]] whileTrue:
                [aBlock value: i.
                i := i + self unity]
        ]
]



This to:do:butPleaseExitIf: selector allows you to use expressions like:



1 to: 10 do: [:x | x printNl.] butPleaseExitIf: [:x | x = 3.]



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Canol Gökel
Reply | Threaded
Open this post in threaded view
|

Re: Re: How to exit loops?

Paolo Bonzini-2
In reply to this post by Nicolas Cellier-3
> Forgot a usual fourth way:

you also forgot an "un" before usual, didn't you? :-)

nice trick, but i've never seen it anywhere!

> 4) use a Stream.
>
> exit := false.
> stream := (1 to: 10) readStream.
> [ exitLoop or: [stream atEnd]]
>     whileFalse: [| x |
>         x := stream next.
>         x = 3
>             ifTrue: [exit := true]
>             ifFalse: [...]].

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: Re: How to exit loops?

Paolo Bonzini-2
In reply to this post by ZuLuuuuuu
> Thank you for your answers, I also found a solution by extending the Number
> class like this:

Nice solution (together with Lukas's).  Has the advantage that *you*
were able to make it up!

> 1 to: 10 do: [:x | x printNl.] butPleaseExitIf: [:x | x = 3.]

Or #to:do:whileFalse:

Paolo


_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Reply | Threaded
Open this post in threaded view
|

Re: How to exit loops?

ZuLuuuuuu
Paolo Bonzini <bonzini <at> gnu.org> writes:

> Nice solution (together with Lukas's).  Has the advantage that *you*
> were able to make it up!
>
> Paolo
>


Thanks :)



_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk
Canol Gökel
Reply | Threaded
Open this post in threaded view
|

Re: How to exit loops?

Paolo Bonzini
In reply to this post by Lukas Renggli
Lukas Renggli wrote
My preferred way is the following:

Add the following method to Object (or somewhere else):

Object>>escaper: aBlock
   ^ aBlock value: [ ^ nil ]

Then implement your loop like this:

self escaper: [ :break |
   1 to: 10 do: [ :x |
      x = 3 ifTrue: [ break value ].
      ... ] ]
If you don't care about performance, you can use "Continuation currentDo:" instead of "self escaper:". :-)

As an additional bonus, continuations support both 0- and 1-argument value, so that you can return a value if you wish.

Paolo