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 > > >