Richard Harmon wrote:
I modified Number 'intervals' #to:by:do: method by adding at the beginning:
step = 0 ifTrue: [ ^self error: 'step must be non-zero.' ].
then evaluated:
5 to: 1 by: 0 do: [ :n | ^#bogus].
it returns bogus.
Ralph Johnson replied:
Traditionally to:do: is optimized by the compiler when you send it to a number, so the to:do: method is never called. I bet that Squeak does the same thing with to:by:do:. The problem is that you are catching the compiler cheating.
Yep; there is a hint in the beginning of the method that Richard modified that states this. Richard, the compiler macro-expansions (inlined code) are in the MessageNode class (macro transformations category). If you want to continue to play with this, here is a change to the to:by:do transformation that causes it to not in-line if the step amount is zero.
'From Squeak 2.3 of January 14, 1999 on 30 January 1999 at 8:59:33 am'!
!MessageNode methodsFor: 'macro transformations' stamp: 'tao 1/30/1999 08:56'! transformToDo: encoder " var _ rcvr. L1: [var <= arg1] Bfp(L2) [block body. var _ var + inc] Jmp(L1) L2: " | limit increment block initStmt test incStmt limitInit blockVar | "First check for valid arguments" ((arguments last isMemberOf: BlockNode) and: [arguments last numberOfArguments = 1]) ifFalse: [^ false]. arguments last firstArgument isVariableReference ifFalse: [^ false]. "As with debugger remote vars" arguments size = 3 ifTrue: [increment _ arguments at: 2. (increment isConstantNumber and: [increment literalValue ~= 0]) ifFalse: [^ false]] ifFalse: [increment _ encoder encodeLiteral: 1]. arguments size < 3 ifTrue: "transform to full form" [selector _ SelectorNode new key: #to:by:do: code: #macro].
"Now generate auxiliary structures" block _ arguments last. blockVar _ block firstArgument. initStmt _ AssignmentNode new variable: blockVar value: receiver. limit _ arguments at: 1. limit isVariableReference | limit isConstantNumber ifTrue: [limitInit _ nil] ifFalse: "Need to store limit in a var" [limit _ encoder autoBind: blockVar key , 'LimiT'. limit scope: -2. "Already done parsing block" limitInit _ AssignmentNode new variable: limit value: (arguments at: 1)]. test _ MessageNode new receiver: blockVar selector: (increment key > 0 ifTrue: [#<=] ifFalse: [#>=]) arguments: (Array with: limit) precedence: precedence from: encoder. incStmt _ AssignmentNode new variable: blockVar value: (MessageNode new receiver: blockVar selector: #+ arguments: (Array with: increment) precedence: precedence from: encoder). arguments _ (Array with: limit with: increment with: block) , (Array with: initStmt with: test with: incStmt with: limitInit). ^ true! !
!Number methodsFor: 'intervals' stamp: 'tao 1/30/1999 08:58'! to: stop by: step do: aBlock "Normally compiled in-line, and therefore not overridable. Evaluate aBlock for each element of the interval (self to: stop by: step)." | nextValue | nextValue _ self. step = 0 ifTrue: [self error: 'step must be non-zero']. step < 0 ifTrue: [[stop <= nextValue] whileTrue: [aBlock value: nextValue. nextValue _ nextValue + step]] ifFalse: [[stop >= nextValue] whileTrue: [aBlock value: nextValue. nextValue _ nextValue + step]]! !
-- tim
squeak-dev@lists.squeakfoundation.org