Andy and Blair,
I'm encountering some very strange problems which I think might be VM or COM related. The code in question is as follows: Bar method: onChangedFields: aTwoArgBlock self fooNames do: [ : fnam | self = nil ifTrue:[self halt]. "should never hit this.." (self fooAt: fnam) onChangedFields: [ : fields | "line 5" aTwoArgBlock value: fnam value: fields ] ] "line 6" fooNames is an anOrderedCollection with 'a' 'b' 'c'. If I just run into this code i hit the halt every time at the top of the 2nd iteration. Debugging it, I single-step until line 5 & 6 are highlighted. At this point the following shows in the variables pane in the debugger: self = the receiver aTwoArgBlock = the block passed in fnam = 'a' This is all normal. Then I press "step over". now: self = nil. *sometimes*: aTwoArgBlock = the fooNames collection (an instVar in the receiver) fnam = an instance variable in the receiver ]. I have absolutely definitely seen these 3 values change their contents just by clicking on them in various orders in the debugger. For example with the debugger at the halt just now I clicked on self, it was nil, then clicked on aTwoArgBlock and fnam and they were bad, then clicked back on self and it was back to being the receiver. The problem does depend on the code in line 5 & 6. If i comment "onChangedFields:[ : fields |... ]" the problem goes away. Likewise if I change the implementation of Foo>>#onChangedFields: to a no-op. Foo>>#onChangedFields: looks like this: onChangedFields: aBlock self controlSite when: #ChangedFields: perform: aBlock where controlSite is an AXControlSite. I tried stepping into the #when:perform and as best I can tell, the damage doesnt occur until the stack is unwinding back to the top method. So far, I dont know how to isolate this into a test case. I'm hoping that just the above might yield a clue. My guess is that if there weren't any ActiveX objects involved this problem is NR. It's probably going to be a bear to make a clean test case. But I'll do whatever it takes to help repro it. (This code has another bug which is unrelated to the self problem. The inner blocks are bound to the "wrong" value of "fnam". [perhaps this is a "feature"?]. On Dolphin, (#(1 2) collect: [ :each | [each]]) first value evaluates to 2, whereas on VisualSmalltalk the answer is 1, which is what I expect. Im not sure which one is "standard". But I think I am strongly going to miss the VSE behavior) |
On Thu, 10 Jan 2002 01:22:15 GMT, ar <[hidden email]> wrote:
> On Dolphin, > > (#(1 2) collect: [ :each | [each]]) first value > > evaluates to 2, whereas on VisualSmalltalk the answer is 1, which is what I > expect. Im not sure which one is "standard". But I think I am strongly going > to miss the VSE behavior) Squeak does this, too ... so it's two to one it's a bug in VS :-) What does (#(1 2) collect: [ :each | [each]]) last value give in VSE? I'd say that Dolphin and Squeak are storing references to "an iteration variable" in the block, and after finishing the collect: the binding points to the last element in the sequence. s. |
Stefan Schmiedl wrote:
> > On Thu, 10 Jan 2002 01:22:15 GMT, ar <[hidden email]> wrote: > > > On Dolphin, > > > > (#(1 2) collect: [ :each | [each]]) first value > > > > evaluates to 2, whereas on VisualSmalltalk the answer is 1, which is what I > > expect. Im not sure which one is "standard". But I think I am strongly going > > to miss the VSE behavior) VSE is right, and is exhibiting standard (i.e. ANSI-standard) behaviour. > > Squeak does this, too ... so it's two to one it's a bug in VS :-) You'll find most commercial Smalltalks agree with VS, VisualWorks, VisualAge and Smalltalk Agents included. > > What does > > (#(1 2) collect: [ :each | [each]]) last value > > give in VSE? > > I'd say that Dolphin and Squeak are storing references to "an > iteration variable" in the block, and after finishing the collect: > the binding points to the last element in the sequence. > > s. This is an old bug in the specification/implementation of Smalltalk-80, as given in the blue book. In Smalltalk-76 through Smalltalk-80 block argument variables are actually allocated on the stack frame of the enclosing method context. i.e. in the above there is only one physical memory location being used to represent each. In fact the code could be written | each | #(1 2) collect: [ :each | [each]]. each and it would print 2. This is definitely a bug in Squeak and Dolphin, but an understandable and long standing one. ANSI Smalltalk requires that each each above have a distinct memory location. Of course making this change is, um, non-trivial and potentially has far reaching effects. Andy and Blair are well aware of the issue. Until they fix it, "don't do that" :) -- _______________,,,^..^,,,____________________________ Eliot Miranda Smalltalk - Scene not herd |
On Thu, 10 Jan 2002 23:23:04 GMT, Eliot Miranda <[hidden email]> wrote:
>You'll find most commercial Smalltalks agree with VS, VisualWorks, >VisualAge and Smalltalk Agents included. > >This is an old bug in the specification/implementation of Smalltalk-80, >as given in the blue book. In Smalltalk-76 through Smalltalk-80 block >argument variables are actually allocated on the stack frame of the >enclosing method context. i.e. in the above there is only one physical >memory location being used to represent each. In fact the code could be >written > > | each | > #(1 2) collect: [ :each | [each]]. > each > >and it would print 2. This is definitely a bug in Squeak and Dolphin, >but an understandable and long standing one. ANSI Smalltalk requires >that each each above have a distinct memory location. Of course making >this change is, um, non-trivial and potentially has far reaching >effects. Andy and Blair are well aware of the issue. Until they fix >it, "don't do that" :) Eliot, Coming from VS, it is going to take some "deprogramming" for me to learn to live without it. When I tried to rewrite my original code, I realized it's not so simple to "dont do that". The ANSI behavior is significant. I concluded that the only way in general to translate code which depended on the ANSI behavior is to introduce another method context into the mix. In my example: onChangedFields: aTwoArgBlock self fooNames do: [ : fnam| (self fooAt: fnam) onChangedFields: [ : fields | aTwoArgBlock value: fnam value: fields ] ] becomes: onChangedFields: aTwoArgBlock self fooNames do: [ : fnam | self onChangedFields: aTwoArgBlock in: fnam ] onChangedFields: aTwoArgBlock in: fnam (self fooAt: fnam) onChangedFields: [ : fields | aTwoArgBlock value: fnam value: fields] which is not expressed as well. There appears to be no "trick" for getting each inner block instance to have a distinct value in the single-method version. I'd love to be proven wrong though.. |
ar wrote:
[snip] > There appears to be no "trick" for getting each inner block instance to have a > distinct value in the single-method version. I'd love to be proven wrong > though.. I think you're right; one needs to rewrite the code. There are various rewrites one can imagine that might be less intrusive than yours and might be applicable automatically. But these either break the VM or amount to fixing the problem. -- _______________,,,^..^,,,____________________________ Eliot Miranda Smalltalk - Scene not herd |
Free forum by Nabble | Edit this page |