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.

On Sat, 10 Nov 2018 at 06:17, Roelof Wobben <r.wob...@home.nl> wrote:

> hmm.
>
> When I try this on P7
>
> |input stepChanges floor|
> input := '((('.
> floor := 0.
> stepChanges := input collect: [ :c |
>     floor := floor + (c = '(' ifTrue: [ 1 ] ifFalse: [ -1 ]).
>     floor
> ].
>
> stepChanges detectIndex: [ :each | each = -1 ] ifNone: [ 'invalid input
> yo' ].
>
> then I see this error message :  Improper store to indexable object.
>
> Roelof
>
>
> Op 9-11-2018 om 17:39 schreef Roelof Wobben:
>
> stepChanges := input collect: [ :c |
> floor := floor + (c = '(' ifTrue: [ 1 ] ifFalse: [ -1 ]).
> floor
> ].
>
> stepChanges detectIndex: [ :each | each = -1 ] ifNone: [ 'invalid input
> yo' ].
>
>
>

Reply via email to