Search code examples
refactoringconditional-statementssmalltalkpharo

Multiple ifs in Smalltalk


I'm really new to smalltalk and still trying to figure out the basic stuff. Below is a simple program I wrote. It is supposed to print "a" if the number can be divided by 5, "b" if it can be divided by 3, and "ab" if it can be divided by 5 and 3. In any other case, the program just prints the number itself. It certainly works like this, but I feel that the code isn't very pretty - I would like to avoid the third "if", but I'm really not sure how. How would you refactor this?

1 to: 100 do: [ :i | 
  (i % 5 == 0)
  ifTrue: [ Transcript show: 'a' ].
  (i % 3 == 0)
  ifTrue: [ Transcript show: 'b' ].
  ((i % 3 == 0) or:  (i % 5 == 0))
  ifFalse: [ Transcript show: i ].
  Transcript cr.
].

Thanks in advance for your help!


Solution

  • Smells like a Fizz Buzz problem! :-)

    One approach in Smalltalk (Pharo) I've seen that I like is to use a dictionary with the Fizz and/or Buzz words as values and the booleans for whether it's divisible by 3 and 5 as keys. Once you have that, you simply look up the value for each index between 1 and 100. Oh, and don't bother dividing and checking whether the remainder is zero yourself - it's Smalltalk, so a number should know whether it's divisible by another number.

    | fizzbuzz |
    fizzbuzz := Dictionary
        with: #(true true)->'FizzBuzz'
        with: #(true false)->'Fizz'
        with: #(false true)->'Buzz'.
    1 to: 100 do: [ :eachIndex |
        Transcript
            show: (fizzbuzz
                at: {eachIndex isDivisibleBy: 3. eachIndex isDivisibleBy: 5}
                ifAbsent: [ eachIndex ]);
            cr]
    

    Have a look at some of the other examples as well, sometimes the different approaches can be quite educational. I'll leave it to you to adapt the code to your 'a'/'b'/'ab' example.