[bug] Collection newWithAll: in 0.3.1

Tim Olson tim at io.com
Tue Dec 14 17:43:43 PST 2004


On Dec 14, 2004, at 5:51 PM, Daniel John Crowe wrote:

>
> There is a missing period on the second last line in this method. 
> (Just looked at CVS and found this is fixed)
>
> I had trouble when trying to fix this in my image.
> I fixed collection.slate and then reloaded it, but the problem still 
> remained.  Note: I was using Set, but could not find any other 
> definitions of this method.
>
> Can you explain this to me?

Interesting problem -- it took some digging to find out what is 
actually going on.

I assume you mean the bug is in extensible.slate (ExtensibleCollection).

Looking at the bytecode for the various methods without the fix:

====
Slate 3> (Method findNamed: #newWithAll: on: {Set. {1. 2. 3}}) code.
{"ByteArray" 6. 1. 17. 32.
         34. 23. 22. 33.
         38. 17. 16. 32}
Slate 4> (Method findNamed: #newWithAll: on: {ExtensibleCollection. {1. 
2. 3}}) code.
{"ByteArray" 6. 1. 17. 32.
         34. 23. 22. 33.
         38. 17. 16. 32}
====

So we see that Set is using the same method defined in 
ExtensibleCollection.  If we load the fixed extensible.slate:

====
Slate 5> load: 'src/lib/extensible.slate'.
Loading 'src/lib/extensible.slate'
Nil
Slate 6> (Method findNamed: #newWithAll: on: {ExtensibleCollection. {1. 
2. 3}}) code.
{"ByteArray" 6. 1. 17. 32.
         34. 22. 33. 17.
         32. 39. 33}
Slate 7> (Method findNamed: #newWithAll: on: {Set. {1. 2. 3}}) code.
{"ByteArray" 6. 1. 17. 32.
         34. 23. 22. 33.
         38. 17. 16. 32}
====

So loading the new source has modified the method for 
ExtensibleCollection, but not for Set.  However, if we simply redefine 
the faulty method rather than loading all of extensible.slate, it works 
as expected.

The problem appears to be at the beginning of extensible.slate:

	collections addPrototype: #ExtensibleCollection derivedFrom: 
{Collection}.

which appears to be adding a new prototype without adjusting all 
previously-derived subtypes to point to the new prototype.

There is code in derivable.slate which looks like it should handle this 
particular case:

====
x@(Root traits) addPrototype: protoName derivedFrom: parents
"Creates a new prototype with the given name, handles derive calls
transparently, and sets the traits name slot to the name for 
convenience."
[| newProto |
   newProto: (parents size = 1
     ifTrue: [(parents at: 0) derive]
     ifFalse:
       [| others index |
         others: (parents newSize: parents size - 1).
         index: others size.
         [index = 0]
           whileFalse:
             [index: index - 1.
               others at: index put: (parents at: index + 1)].
         (parents at: 0) derive &mixins: others]).
   "ensureSlot:is: may return the old value if =, but always returns what
   is installed after the method is done."
   (x hasSlotNamed: protoName)
     ifTrue: [x ensureSlot: protoName is: newProto
                unlessSatisfies: [| :old | old traits delegateValues
                                    = newProto traits delegateValues]]
     ifFalse: [x addImmutableSlot: protoName valued: newProto].
====

The  ensureSlot:is:unlessSatisfies: should have handled this case, but 
the equality test between the old traits delegateValues and the 
newProto traits delegateValues fails because the order of the traits is 
different:

	old: delegateValues: {#traits. #parent0}
	new: delegateValues: {#parent0. #traits}

So it looks like we need to ensure that the delegateValues are returned 
in a canonical order for this code to do the expected thing.

	-- tim




More information about the Slate mailing list