[Newbie] loop-Konstrukt

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

[Newbie] loop-Konstrukt

Enrico Schwass
Moin

Im Netz habe ich eine recht gute Zusammenfassung der Squeak-Iteratoren
gefunden. Mir fiel aber auf, das eine Art "loop"-"break" nicht
aufgeführt ist. Hier mal als Pseudo-Code fuers Lesen einer Textdatei.

ios := FileStream...
...
loop: [
  counter := counter + 1.
  char := ios next.

  (char = nil) iftrue: break.
  (char = '\n') iftrue: break.
  (counter > 255) iftrue: break.

]

Gibts das so nicht? Mit whileTrue: liesse sich das schöner loesen??
Ganz so heimisch fuehle ich mich in Smalltalk noch nicht :/

Bis dann
Enno


Reply | Threaded
Open this post in threaded view
|

Re: [Newbie] loop-Konstrukt

Bert Freudenberg-3

Am 15.11.2005 um 09:58 schrieb Enrico Schwass:

> Moin
>
> Im Netz habe ich eine recht gute Zusammenfassung der Squeak-Iteratoren
> gefunden. Mir fiel aber auf, das eine Art "loop"-"break" nicht
> aufgeführt ist. Hier mal als Pseudo-Code fuers Lesen einer Textdatei.
>
> ios := FileStream...
> ...
> loop: [
>   counter := counter + 1.
>   char := ios next.
>
>   (char = nil) iftrue: break.
>   (char = '\n') iftrue: break.
>   (counter > 255) iftrue: break.
>
> ]
>
> Gibts das so nicht? Mit whileTrue: liesse sich das schöner loesen??
> Ganz so heimisch fuehle ich mich in Smalltalk noch nicht :/
Merkt man - du versuchst gerade, das Problem mit der "guten alten"  
Spaghetti-Code-Methode anzugehen.

Ein "break" ist nichts weiter als ein GOTO *hinter* das Ende der  
Schleife, stimmt's? Du willst also aus einem Block (das Objekt, das  
du mit "[...]" erzeugst) hinter den Message-send von #loop: springen.  
Dieser Block wird aber wo ganz anders abgearbeitet, nämlich tief  
verschachtelt unten in der #loop:-Methode.

*Wenn* man das unbedingt will, gibt es natürlich Möglichkeiten, um  
über mehrere Ebenen der Aufrufkette zurückzuspringen: nicht-lokale  
Returns, und Exceptions. Ein nicht-lokales Return ist eins, das nicht  
frei am Ende der Methode, sondern in einem Block steht (also z.B. in  
einem von deinen #ifTrue:-Zweigen). Exceptions sollten klar sein, die  
sind prinzipiell wie in anderen Sprachen auch. Damit könnte man also  
das Break nachbauen:

| n |
n := 0.
(1 to: 10) loop: [:i | i even ifTrue: [n := i. self loopBreak]].
n "ergibt 2"

=========

loop: aBlock
        ^ [self do: aBlock] on: LoopBreak do: [:ex | ex return]

loopBreak
        ^LoopBreak signal

=========

Der vollständige Code ist im Anhang.

Aber das macht man normalerweise nicht. Höchstens um zu  
demonstrieren, wie einfach es ist, in Smalltalk neue  
Kontrollstrukturen einzubauen ;-)

Was genau versuchst du denn eigentlich, da zu tun? Sieht aus wie der  
Versuch, Low-Level-C++-Code eins-zu-eins nach Smalltalk zu portieren.  
Es gibt sicher einen eleganteren Weg.

- Bert -





Bert-LoopBreak-bf.1.mcz (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Newbie] loop-Konstrukt

Enrico Schwass
Hallo

> > Im Netz habe ich eine recht gute Zusammenfassung der Squeak-Iteratoren
> > gefunden. Mir fiel aber auf, das eine Art "loop"-"break" nicht
> > aufgeführt ist. Hier mal als Pseudo-Code fuers Lesen einer Textdatei.
> > ios := FileStream...
> > ...
> > loop: [
> >   counter := counter + 1.
> >   char := ios next.
> >   (char = nil) iftrue: break.
> >   (char = '\n') iftrue: break.
> >   (counter > 255) iftrue: break.
> > ]
> > Gibts das so nicht? Mit whileTrue: liesse sich das schöner loesen??
> > Ganz so heimisch fuehle ich mich in Smalltalk noch nicht :/
> Merkt man - du versuchst gerade, das Problem mit der "guten alten"  
> Spaghetti-Code-Methode anzugehen.

Huch...

> Ein "break" ist nichts weiter als ein GOTO *hinter* das Ende der  
> Schleife, stimmt's?

Ja. Lies bis zum naechsten LineFeed, aber nicht mehr als 256 Zeichen
oder bis der Stream zu Ende ist. Man haette das noch mit "oder"
verknuepfen koennen, aber obs da uebersichtlicher wird ...

> Du willst also aus einem Block (das Objekt, das  
> du mit "[...]" erzeugst) hinter den Message-send von #loop: springen.  
> Dieser Block wird aber wo ganz anders abgearbeitet, nämlich tief  
> verschachtelt unten in der #loop:-Methode.

Vermutlich ist oben mein Pseudo-Code falsch verstaendlich. In Ruby sehe
das so aus

counter = 0
loop do
        counter = counter.succ
        char = STDIN.getc
        break if char == 10
        break if counter > 255
# ....
end

> *Wenn* man das unbedingt will, gibt es natürlich Möglichkeiten, um  
> über mehrere Ebenen der Aufrufkette zurückzuspringen: nicht-lokale  
> Returns, und Exceptions. Ein nicht-lokales Return ist eins, das nicht  
> frei am Ende der Methode, sondern in einem Block steht (also z.B. in  
> einem von deinen #ifTrue:-Zweigen). Exceptions sollten klar sein, die  
> sind prinzipiell wie in anderen Sprachen auch. Damit könnte man also  
> das Break nachbauen:
>
> | n |
> n := 0.
> (1 to: 10) loop: [:i | i even ifTrue: [n := i. self loopBreak]].
> n "ergibt 2"
>
> =========
>
> loop: aBlock
> ^ [self do: aBlock] on: LoopBreak do: [:ex | ex return]
>
> loopBreak
> ^LoopBreak signal
>
> =========
>
> Der vollständige Code ist im Anhang.
>
> Aber das macht man normalerweise nicht. Höchstens um zu  
> demonstrieren, wie einfach es ist, in Smalltalk neue  
> Kontrollstrukturen einzubauen ;-)

loop ist in Ruby eine Endlosschleife. Das habe ich nicht erwaehnt.
Alle anderen Iteratoren gibt es aber auch. Besten Dank fuer den
Beispielcode. Ist ungewohnt fuer meine Augen, das mag aber an der
Uhrzeit liegen.

In meinem Einsteiger-Smalltalk-Buch steht nichts zu Exceptions. Oder ich
habs aufgrund des miserablen Index uebersehen.

> Was genau versuchst du denn eigentlich, da zu tun? Sieht aus wie der  
> Versuch, Low-Level-C++-Code eins-zu-eins nach Smalltalk zu portieren.  
> Es gibt sicher einen eleganteren Weg.

siehe oben. Ich lasse mir sehr gerne elegante Wege zeigen.

Aufgewachsen bin ich mit Z80-Assembler. Das haengt mir seit fast zwei
Jahrzehnten nach. Ich bin ein lausiger Programmierer :)

Bis dann
Enno


Reply | Threaded
Open this post in threaded view
|

Re: [Newbie] loop-Konstrukt

Bert Freudenberg-3
Am 15.11.2005 um 23:49 schrieb Enrico Schwass:

> Vermutlich ist oben mein Pseudo-Code falsch verstaendlich. In Ruby  
> sehe
> das so aus
>
> counter = 0
> loop do
> counter = counter.succ
> char = STDIN.getc
> break if char == 10
> break if counter > 255
> # ....
> end
>
> loop ist in Ruby eine Endlosschleife.


Wie du schon vermutetest, würde man das üblicherweise mit #while...  
erledigen:

counter := 0.
[
        counter := counter + 1.
        char := stream next.
        char isNil or: [char asInteger = 10 or: [counter > 255]]
] whileFalse.

Es gibt auch #repeat als Endlosschleife, sieht man aber eher selten,  
und wird dann üblicherweise mit nicht-lokalen Returns kombiniert:

counter := 0.
[
        counter := counter + 1.
        char := stream next.
        char ifNil: [^self].
        char asInteger = 10 ifTrue: [^self].
        counter > 255 ifTrue: [^self].
] repeat.

Da dann nach der Schleife natürlich nichts mehr folgen kann, macht  
man daraus eine eigene Methode. Was anerkanntermaßen sowieso meist  
eine gute Idee ist ;-)

- Bert -


Reply | Threaded
Open this post in threaded view
|

Re: [Newbie] loop-Konstrukt

Enrico Schwass
Moin

> Wie du schon vermutetest, würde man das üblicherweise mit #while...  
> erledigen:
>
> counter := 0.
> [
> counter := counter + 1.
> char := stream next.
> char isNil or: [char asInteger = 10 or: [counter > 255]]
> ] whileFalse.

Die Methode bzw. der Block liefert dann true zurueck. Noch besser waers
natuerlich, wenn der Block gleich "endOfFile" oder "lineTooLong" als
Ergebnis bekommen koennte. Geht das ohne Benutzung einer "errcode"
Variablen?? Vor ein paar Monaten noch haette ich das mit "case" etc
geloest, aber ich hoere schon den Aufschrei in der Smalltalk-Welt :)

> Da dann nach der Schleife natürlich nichts mehr folgen kann, macht  
> man daraus eine eigene Methode. Was anerkanntermaßen sowieso meist  
> eine gute Idee ist ;-)

Alles ueber acht Zeilen soll man refactorieren, hab ich gelesen. Wenn
ich mir meine alten Programme so anschaue, waere es einfacher ALLES neu
zu schreiben :)

Leider ist die Auswahl an deutschsprachigen Smalltalk-Buechern, die mehr
als nur die Syntax vermitteln nicht so reichhaltig

Bis dann
Enno