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 |
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 :/ 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 |
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 |
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 - |
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 |
Free forum by Nabble | Edit this page |