The code I have trouble with is in my workspace where I execute via
'DoIt'
<code> |contacts copy| contacts := MyContact contacts. copy := contacts deepCopy. (contacts = copy) ifTrue: [true inspect] ifFalse: [false inspect] </copy> When I use #copy instead of #deepCopy the code correctly enters the ifTrue path. Both contacts and copy show the same under inspection and explore. all inst vars: array: an Array(nil nil a MyContact a MyContact nil nil nil nil nil nil) firstIndex: 3 lastIndex: 4 Class methods for MyContact: <code> contacts "Answers the storage for contacts" Database isNil ifTrue: [self createSampleDatabase]. ^ Database createSampleDatabase Database := (OrderedCollection new) add: (self name: 'Bob Jones' emailAddress: '[hidden email]'); add: (self name: 'Steve Smith' emailAddress: '[hidden email]'); yourself </code> Database is an instance variable of MyContact. The code failing is in the method <code> hasEqualElements: otherCollection "Answer whether the receiver's size is the same as otherCollection's size, and each of the receiver's elements equal the corresponding element of otherCollection. This should probably replace the current definition of #= ." | size | (otherCollection isKindOf: SequenceableCollection) ifFalse: [^ false]. (size := self size) = otherCollection size ifFalse: [^ false]. 1 to: size do: [:index | (self at: index) = (otherCollection at: index) ifFalse: [^ false]]. ^ true = anObject "Answer whether the receiver and the argument represent the same object. If = is redefined in any subclass, consider also redefining the message hash." ^self == anObject </code> The '#=' code executes a '#==' and fails. Why is it excuting '#==' ? Obviously it would fail for deepCopy. Thanks _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Hello.
The code eventually executes #== (inherited from Object) to compare two MyContact instances, because MyContact does not define its own version of #=. You can of course implement it to something like this: MyContact>>= anObject ^self class == anObject class and: [name = anObject name and: [emailAddress = anObject emailAddress]]. And, as noted in Object>>=, you should define your own version of #hash as well if you do so: MyContact>>hash ^(self class identityHash bitXor: name hash) bitXor: emailAddress hash. All objects for which #= evaluates to true must have the same #hash value. The #hash is used for quick lookup in Set and Dictionary collections. HTH, Ladislav Lenart On 3.5.2011 06:09, intrader wrote: > The code I have trouble with is in my workspace where I execute via 'DoIt' > <code> > |contacts copy| > contacts := MyContact contacts. > copy := contacts deepCopy. > (contacts = copy) ifTrue: [true inspect] > ifFalse: [false inspect] > </copy> > When I use #copy instead of #deepCopy the code correctly enters the ifTrue path. Both contacts and copy show the same under inspection and explore. > all inst vars: > array: an Array(nil nil a MyContact a MyContact nil nil nil nil nil nil) > firstIndex: 3 > lastIndex: 4 > > Class methods for MyContact: > <code> > contacts > "Answers the storage for contacts" > Database isNil ifTrue: [self createSampleDatabase]. > ^ Database > createSampleDatabase > Database := (OrderedCollection new) > add: (self name: 'Bob Jones' emailAddress: '[hidden email]'); > add: (self name: 'Steve Smith' emailAddress: '[hidden email]'); > yourself > </code> > Database is an instance variable of MyContact. > The code failing is in the method > <code> > hasEqualElements: otherCollection > "Answer whether the receiver's size is the same as otherCollection's > size, and each of the receiver's elements equal the corresponding > element of otherCollection. > This should probably replace the current definition of #= ." > > | size | > (otherCollection isKindOf: SequenceableCollection) ifFalse: [^ false]. > (size := self size) = otherCollection size ifFalse: [^ false]. > 1 to: size do: > [:index | > (self at: index) = (otherCollection at: index) ifFalse: [^ false]]. > ^ true > = anObject > "Answer whether the receiver and the argument represent the same > object. If = is redefined in any subclass, consider also redefining the > message hash." > > ^self == anObject > </code> > The '#=' code executes a '#==' and fails. Why is it excuting '#==' ? Obviously it would fail for deepCopy. > > Thanks > > > > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
The answer is simple.
Simple #copy prefers to do #shallowCopy, i.e. make a copy where all inst.vars are identical to the original. A #deepCopy creates new objects on every level in the depth, until all nodes in the original object graph have copied counterparts. When you make a comparison, the default test is for identity. If you have your own implementation of #=, then you will check equality of various inst.vars. But it is very likely that your object graph contains instances from "system" classes, i.e. classes that are not from your domain. These classes have their own understanding of being equal, in particular those that simply inherit #= from Object with "^self == anObject", then the equality test *must* fail at a certain level. This means that "x = x deepCopy" should return false *in general*, unless the object graph of x contains only instances from your domain or from "simple" data types, such as Number, String, Date, etc. Smalltalk is such a wonderful environment where you can learn how the equality test is done by simple use of the Debugger. Just run "x = x deepCopy" with your favorite object x, and use "Debug it" instead of "Do it". Follow the flow by stepping into each comparison and wait for your "aah" effect. Cheers Holger Am 03.05.2011 10:56, schrieb Ladislav Lenart: > Hello. > > The code eventually executes #== (inherited from Object) to > compare two MyContact instances, because MyContact does not > define its own version of #=. You can of course implement > it to something like this: > > MyContact>>= anObject > > ^self class == anObject class > and: [name = anObject name > and: [emailAddress = anObject emailAddress]]. > > > And, as noted in Object>>=, you should define your own > version of #hash as well if you do so: > > MyContact>>hash > > ^(self class identityHash bitXor: name hash) bitXor: emailAddress hash. > > > All objects for which #= evaluates to true must have the > same #hash value. The #hash is used for quick lookup in > Set and Dictionary collections. > > > HTH, > > Ladislav Lenart > > > On 3.5.2011 06:09, intrader wrote: >> The code I have trouble with is in my workspace where I execute via 'DoIt' >> <code> >> |contacts copy| >> contacts := MyContact contacts. >> copy := contacts deepCopy. >> (contacts = copy) ifTrue: [true inspect] >> ifFalse: [false inspect] >> </copy> >> When I use #copy instead of #deepCopy the code correctly enters the ifTrue path. Both contacts and copy show the same under inspection and explore. >> all inst vars: >> array: an Array(nil nil a MyContact a MyContact nil nil nil nil nil nil) >> firstIndex: 3 >> lastIndex: 4 >> >> Class methods for MyContact: >> <code> >> contacts >> "Answers the storage for contacts" >> Database isNil ifTrue: [self createSampleDatabase]. >> ^ Database >> createSampleDatabase >> Database := (OrderedCollection new) >> add: (self name: 'Bob Jones' emailAddress: '[hidden email]'); >> add: (self name: 'Steve Smith' emailAddress: '[hidden email]'); >> yourself >> </code> >> Database is an instance variable of MyContact. >> The code failing is in the method >> <code> >> hasEqualElements: otherCollection >> "Answer whether the receiver's size is the same as otherCollection's >> size, and each of the receiver's elements equal the corresponding >> element of otherCollection. >> This should probably replace the current definition of #= ." >> >> | size | >> (otherCollection isKindOf: SequenceableCollection) ifFalse: [^ false]. >> (size := self size) = otherCollection size ifFalse: [^ false]. >> 1 to: size do: >> [:index | >> (self at: index) = (otherCollection at: index) ifFalse: [^ false]]. >> ^ true >> = anObject >> "Answer whether the receiver and the argument represent the same >> object. If = is redefined in any subclass, consider also redefining the >> message hash." >> >> ^self == anObject >> </code> >> The '#=' code executes a '#==' and fails. Why is it excuting '#==' ? Obviously it would fail for deepCopy. >> >> Thanks >> >> >> >> >> _______________________________________________ >> vwnc mailing list >> [hidden email] >> http://lists.cs.uiuc.edu/mailman/listinfo/vwnc > > _______________________________________________ > vwnc mailing list > [hidden email] > http://lists.cs.uiuc.edu/mailman/listinfo/vwnc _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
I note that there is no #deepCopy method in the base system. There
used to be, a very long time ago, but it was removed because of the
ambiguity of what it was actually expected to do in different cases.
So if you're using it, it's presumably been added by you or by some
package you're using.
--
[hidden email] [hidden email] http://www.cincomsmalltalk.com _______________________________________________ vwnc mailing list [hidden email] http://lists.cs.uiuc.edu/mailman/listinfo/vwnc |
Free forum by Nabble | Edit this page |