hi, i have a testsuite that is a subclass of TestCase with this method: testStupid |a| a :=#(1). self assert: a first isNumber . a :=a at:1 put: nil. if i run the test once, it succeeds, but but when i run it a second time it fails. this seems to be sligthly counterintuitive, or how do i have to understand it? werner
Hi Werner, On 12 Apr 2011, at 23:47, Werner Kassens wrote:
hi, i have a testsuite that is a subclass of TestCase with this method:
testStupid |a| a :=#(1). self assert: a first isNumber . a :=a at:1 put: nil.
if i run the test once, it succeeds, but but when i run it a second time it fails. this seems to be sligthly counterintuitive, or how do i have to understand it?
werner
You are destructively modifying a constant, the literal array #(1), of which there is one instance attached to #testStupid'd compiled method. Sven
On 12 avr. 2011, at 23:47, Werner Kassens wrote:
hi, i have a testsuite that is a subclass of TestCase with this method:
testStupid |a| a :=#(1). self assert: a first isNumber . a :=a at:1 put: nil.
if i run the test once, it succeeds, but but when i run it a second time it fails. this seems to be sligthly counterintuitive, or how do i have to understand it?
Interesting, I would never have guessed the test would be broken at first sight. So maybe some people enlightened in the ways of the compiler can provide a better explanation than me. Here is my guess: #(1) is a special construct which creates a compile-time array. The compile-time makes the trick: in short the array is more or less encoded directly into the bytecodes of the method as a constant. But modifying the array with #at:put: directly modifies the bytecodes in the compiled method itself. So you create a side-effect directly into your method. Am I the only one to find this a bit dangerous and not intuitive? Is it a well-known behavior? A correct way to fix that would be to use a dynamic array {1} or define a setUp method which would initialize the array before each run. -- Simon Denier
On Apr 12, 2011, at 3:24 PM, Simon Denier wrote:
On 12 avr. 2011, at 23:47, Werner Kassens wrote:
hi, i have a testsuite that is a subclass of TestCase with this method:
testStupid |a| a :=#(1). self assert: a first isNumber . a :=a at:1 put: nil.
if i run the test once, it succeeds, but but when i run it a second time it fails. this seems to be sligthly counterintuitive, or how do i have to understand it?
Interesting, I would never have guessed the test would be broken at first sight. So maybe some people enlightened in the ways of the compiler can provide a better explanation than me. Here is my guess:
#(1) is a special construct which creates a compile-time array. The compile-time makes the trick: in short the array is more or less encoded directly into the bytecodes of the method as a constant. But modifying the array with #at:put: directly modifies the bytecodes in the compiled method itself. So you create a side-effect directly into your method.
Am I the only one to find this a bit dangerous and not intuitive? Is it a well-known behavior?
I would never have guessed that in a million years. Pat
Interesting, I would never have guessed the test would be broken at first sight. So maybe some people enlightened in the ways of the compiler can provide a better explanation than me. Here is my guess:
#(1) is a special construct which creates a compile-time array. The compile-time makes the trick: in short the array is more or less encoded directly into the bytecodes of the method as a constant. But modifying the array with #at:put: directly modifies the bytecodes in the compiled method itself. So you create a side-effect directly into your method.
Am I the only one to find this a bit dangerous and not intuitive? Is it a well-known behavior?
I would never have guessed that in a million years. welcome to the time traveling machine
it is a bit ugly and nobody should rely on such bad behavior. Consider that it should not exist. Stef
hi, i have a testsuite that is a subclass of TestCase with this method:
testStupid |a| a :=#(1). self assert: a first isNumber . a :=a at:1 put: nil.
if i run the test once, it succeeds, but but when i run it a second time it fails. this seems to be sligthly counterintuitive, or how do i have to understand it?
Interesting, I would never have guessed the test would be broken at first sight. So maybe some people enlightened in the ways of the compiler can provide a better explanation than me. Here is my guess:
#(1) is a special construct which creates a compile-time array. The compile-time makes the trick: in short the array is more or less encoded directly into the bytecodes of the method as a constant. But modifying the array with #at:put: directly modifies the bytecodes in the compiled method itself. So you create a side-effect directly into your method.
Am I the only one to find this a bit dangerous and not intuitive? Is it a well-known behavior?
It is clearly ugly. Here what you see is a modification of the literal object that is stored in the compiled method literal frame. This is a well know limit of Smalltalk implementation. Having immutable literal objects may solve this problem. You get the same if you modify a string since this is a container of characters. This is like the optimization of similar literal strings that breaks the fact that 'foo' == 'foo' return false. normally yes this is false but when on the same method you get the same literal. Stef
participants (6)
-
Pat Maddox -
Simon Denier -
Stéphane Ducasse -
Stéphane Ducasse -
Sven Van Caekenberghe -
Werner Kassens