Thanks for all the explanations.

and yes, I have to get a feel when I need a new class and when not.
and when it's "allowed" to use a if then and when not.

and if I understand the explanations I did not ask a class something so a if then is
allowed.

Roelof



Op 28-11-2018 om 09:01 schreef Richard O'Keefe:
DRAT!  What (genius negated) designed gmail's interface?

If I am wrong that the canHandleInput: class method of
IllegalMoveSanta should return false, not true (because
the order of the elements of #subclasses is not defined,
so that IllegalMoveSanta might *always* be selected),
then that is further evidence that avoiding "if" made
the code LESS readable.

You are a beginner at this, doing all the right things
for a beginner to do.  One of the things you have to do
is to develop a sense of "smell" for code.  Each class
ought to "pull its weight".  Four classes -- which it
really does not make sense to instantiate, just put the
instance methods on the class side and drop the #new --
just to avoid a couple of very clear "ifs"?  I don't
think so.  IF THESE CLASSES NEEDED TO EXIST FOR SOME
OTHER REASON, if they had real work to do, sure.  But
they don't.  They only bloat and obscure the code.



On Wed, 28 Nov 2018 at 20:54, Richard O'Keefe <rao...@gmail.com> wrote:
In Advent-of-Code 2015, the first problem is
really quite simple.  There are at least two
ways to think about it.
"CS101":
   set a counter to 0
   for each character of the string
     if it is '(' increment the counter
     if it is ')' decrement the counter
   report the counter

"Higher level":
   report the difference between
     (the number of '(' characters in the string) and
     (the number of ')' characters in the string).

Expressed in Smalltalk this looks something like
  Transcript print:
    (s occurrencesOf: $() - (s occurrencesOf: $)); cr.

Make no mistake: you *cannot* tell the difference
between $( and $) using class-based dispatch because
they belong to the same class.  There has to be an
"if" somewhere, the question is not whether but where.
In this case, counting the number of occurrences of an
object in a collection is has been a standard Collection
method for nearly 40 years; it's one of the basic
operations you need to learn.

The "higher level" approach can be less efficient that
the "CS101" approach, but in a case like this we really
do not care.  We want the code to be *clear*.

What about the second part of the problem?
Not having submitted any answers, I can't actually
see the second part on the AOC site, but luckily you
have included it in your program.

We want to
   [find the first place] where
      [the cumulative sum] of (c=$()
      [minus]
      [the cumulative sum] of (c=$))
      equals -1.

The "CS101" approach is
   n := i := 0.
   while n >= 0 and i < size(s) do
      i +:= 1
      if s[i] = $( then n := n + 1
      if s[i] = $) then n := n - 1
   report n

The "higher level" approach looks something like
  n := (s cumCount: [:each | each = $(]) -
       (s cumCount: [:each | each = $)])
       indexOf: -1.
-- although it gives 0 instead of s size + 1 when
-1 is never reached.

Here #indexOf: is standard, #- is defined on sequences
in Squeak and Pharo, but #cumCount: does not
exist.  So we need something like

    cumCount: aBlock       
      |c a|       
      a := Array new: self size.
      c := 0.
      self withIndexDo: [:each :i |
        (aBlock value: each) ifTrue: [c := c + 1].
        a at: i put: c].
      ^a
This is *not* coupled to the particular use we have
in mind for it; it is in no way tied to characters
or strings.  It's quite general.

Note: we do not need any new classes, except maybe
a place to put one problem-specific method.

While this answer, with no loop and no if in the
problem-specific code, is quite pretty, it has a
problem.  Suppose the string to have M characters
and the desired step to be number K.  The CS101
approach takes O(K) time and no allocations, but
the higher level approach takes O(M) time and
allocates three M-element Arrays.  (In a non-strict
functional language like Haskell, the higher level
version *also* takes O(K) time, and with a good
enough "deforesting" compiler should allocate no
data structures.)

For a problem like this, I really don't care about
the efficiency aspect.  If I *do* care about that,
then starting from a higher level version gives me
something to test a lower level version against.

To get an efficient answer to the second part,
we still don't need a new semantic class, just
some place to put the code.

Day1
  class methods:
    indexOfFirstBasementTime: steps
      |floor|
      floor := 0.
      steps keysAndValuesDo: [:i :each |
        each = $( ifTrue: [floor := floor + 1].
        each = $) ifTrue: [floor := floor - 1].
        floor = -1 ifTrue: [^i]].
      ^0 "same convention as #indexOf:"

Does this contain "if"?  Why yes, it does.
Is there any problem with that?  Why no, there isn't.
You need to treat members of the same class (left
parenthesis, right parenthesis, others) differently.
You need to treat members of the same class (minus
one, all other integers) differently.
Would there be any gain in clarity or maintainability
if these ifs were somehow eliminated?  Certainly NOT.

Quite the reverse, in fact.
input2 withIndexDo: [ :element :index | |action| 
action:= SantaAction getActionFor: element. floor := action  doMovementFor: floor .
self hasReachedBasement 
ifTrue: [^ index]].
    ^ '-2'.

There is only one word for this: obfuscated.
I was initially puzzled by your returning -2
instead of the conventional 0 if the basement
is not reached, and then *deeply confused* by
the fact that you are returning a *string* in
this case.

Looking at your code, I was further confused
by variables called 'aSymbol' whose value is
always and only a Character, never a Symbol.
And if I am wrong that
IllegalMoveSanta class>> canHandleInput:
in Smalltalk is to return 0 when something is
      
approach



We want to find the first place where something
becomes true.  There are again at least to approaches. 

On Wed, 28 Nov 2018 at 05:41, Roelof Wobben <r.wob...@home.nl> wrote:
Hello,

Yesterday I had a talk with luc frabresse about using if then.
He said if I understand it right, Its the best to not using a if then or
a ifTrue/ifFalse.

Can anyone help me figure out how to rewrite this project so I will not
use the ifTrue in the basement function.

my code so far can be found here : https://github.com/RoelofWobben/AOC2015

Roelof



Reply via email to