We are talking to a beginner here.
One of the important things for a beginner to
understand is the idea of hiding stuff and
thinking in terms of asking objects to do things
for you.�� For example, in Java you historically
did
�� �� final int n = aString.length();
�� �� for (int i = 0; i < n; i++) {
�� �� �� �� final char c = aString.charAt(i);
�� �� �� �� ...
�� �� }
Here all the loop control is *outside* the string, and
if you wanted to use some other data structure you
would have to change the code.�� But in Smalltalk, you
ask the *object* to manage the iteration.
For collections in general, we have
�� aCollection do: [:anElement | ... ]
For sequences we also have
�� aSequence withIndexDo: [:anElement :itsIndex | ...]
where the sequence need not be a stored sequence and
need not be efficiently indexable.�� (And indeed, in
Java these days, Strings *aren't* efficiently
indexable, thanks to using UTF-16 internally.)
Using enumeration methods
(a) makes your code easier to read
(b) makes your code easier to write (as there
�� �� is lots of fiddly detail you don't write at
�� �� all, it's there once and for all in the class)
(c) makes your code more adaptable (the object
�� �� needs to support #withIndexDo: and that is
�� �� *all* you demand of it).
�� ��indexWhereBasementFirstReached: input
�� �� ��"The input is a sequence in which the character
�� �� �� ( means to go up a floor and the character )
�� �� �� means to go down a floor.�� Answer the index
�� �� �� of the character where the floor below the
�� �� �� initial floor is first reached.�� If that
�� �� �� floor is not reached, e.g., if the input is
�� �� �� empty, answer 0. This is the same convention
�� �� �� as #indexOf:."
�� �� ��|floor|
�� �� ��floor := 0.
�� �� ��input withIndexDo: [:char :index |
�� �� �� ��char = $( ifTrue: [floor := floor��+ 1].
�� �� �� ��char = $) ifTrue: [floor := floor - 1].
�� �� �� ��floor = -1 ifTrue: [^index]].
�� �� �� ^0
For example, we could add the #withIndexDo: method to
Stream, which already has #do:
�� �� withIndexDo: elementAndIndexBlock
�� �� �� "Iterate over the 'future values' remaining in
�� �� �� ��this stream, passing each in turn to the block
�� �� �� ��argument, together with an index starting at 1
�� �� �� ��for the first value passed to the block."
�� �� �� |index|
�� �� �� index := 0.
�� �� �� self do: [:each |
�� �� �� �� elementAndIndexBlock value: each value: (index := index��+ 1)].
Now the #indexWhereBasementFirstReached: method will
work on input streams as well as strings, so it could,
for example, handle a terabyte long sequence held in a
file.