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 |
In reply to this post by wernerk
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 |
ah, got it!
thanks werner |
In reply to this post by simondenier
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 |
>>>
welcome to the time traveling machine
>> >> >> 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. it is a bit ugly and nobody should rely on such bad behavior. Consider that it should not exist. Stef |
In reply to this post by simondenier
>
>> 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 |
In reply to this post by simondenier
On Apr 13, 2011, at 5:31 AM, Pat Maddox wrote: > 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. > I like this method: mystery 'mystery' isString ifTrue: ['mystery' become: {0}]. 'mystery' at: 1 put: 'mystery' first + 1. ^ 'mystery' first. -- Marcus Denker -- http://www.marcusdenker.de INRIA Lille -- Nord Europe. Team RMoD. |
On 13 Apr 2011, at 10:00, Marcus Denker wrote: > I like this method: > > mystery > 'mystery' isString ifTrue: ['mystery' become: {0}]. > 'mystery' at: 1 put: 'mystery' first + 1. > ^ 'mystery' first. And you were trying to help newcomers or scare them off ? ;-) This is actually a problem in many languages. It is always better to not touch literals (constants is a dangerour word here). |
Free forum by Nabble | Edit this page |