Consider the method convertToNumber:. This method takes a string as an argument, and answers an integer or a float. This method really adds behavior to a String, so you can move it to the String class as follows:
convertToNumber "Convert the receiver to a number. Answer either an Integer or a Float." | subStrings whole decimal exponent | subStrings := self subStrings: $. . whole := (subStrings at: 1) asNumber. subStrings size = 1 ifTrue: [ ^whole ] ifFalse: [ decimal := subStrings at: 2. (decimal includes: $e) ifTrue: [ subStrings := decimal subStrings: $e. exponent := (subStrings at: 2) asNumber. decimal := subStrings at: 1] ifFalse: [ exponent := 0 ].
^(whole + (decimal asNumber / (10 raisedTo: (decimal size)))) * (10 raisedTo: exponent) asFloat ].
You can delete the convertToNumber: method in the String class.
Now let's use the new String method convertToNumber that you just added:
calculateAnswer: aFunction "Private - Calculate the answer based on lastValue, aFunction, and the current value. Answer a String." | answer last current realFunction | last := lastValue convertToNumber. current := textWidget value convertToNumber. aFunction = '=' ifTrue: [ realFunction := operation ] ifFalse: [ realFunction := aFunction ].
state = #equals ifTrue: [ answer := current perform: (realFunction asSymbol) with: last ] ifFalse: [ answer := last perform: (realFunction asSymbol) with: current ]. answer class = Fraction ifTrue: [ answer := answer asFloat ]. ^answer printString
Let's summarize what you just did. You just gave instances of the String class the ability to convert themselves to numbers. You did that by extending the String class with the method convertToNumber. Why did you move this method to the String class? Because the method convertToNumber is a behavior you might expect strings to have. Thus, it seems that the String class would be a good place to define the behavior.