I have found that a MaClassDefinition instance for one of my domain class still refers to an old definition.
I discover this when updating a readstrategy with an instance variable in the newest class definition but not in the older one (and not in the one defined by the MaClassDefinition instance)
I try to remove the instances of my domain. Close and restart the session. But still I got the oldest definition and obviously the readstrategy definition is causing error.
Hilaire
Hi Hilaire, sorry for the delayed response; I have just returned from a holiday.
Instances of MaClassDefinition are kept for each version of each class that was ever committed to the repository.
When a ReadStrategy is specified, it should work fine for the old and new versions of the classes. See MaReadStrategy>>#convertSpecificationsToIdsUsing: to see that it does indeed create depth-specifications for every known version of the class. The variable that does not exist in the old version will simply
There is no need to "remove" the instance of your domain as it evolves with your class model; the new variables will have nil just like Smalltalk until you populate them and commit.
Can you try again to explain the exact problem you are having? Perhaps a script that reproduces it would improve our mutual clarity?
Regards, Chris
On 7/20/07, Hilaire Fernandes hilaire@ofset.org wrote:
I have found that a MaClassDefinition instance for one of my domain class still refers to an old definition.
I discover this when updating a readstrategy with an instance variable in the newest class definition but not in the older one (and not in the one defined by the MaClassDefinition instance)
I try to remove the instances of my domain. Close and restart the session. But still I got the oldest definition and obviously the readstrategy definition is causing error.
Hilaire
Magma mailing list Magma@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/magma
Le Tue, 24 Jul 2007 22:53:58 -0400, Chris Muller a écrit:
Hi Hilaire, sorry for the delayed response; I have just returned from a holiday.
Instances of MaClassDefinition are kept for each version of each class that was ever committed to the repository.
When a ReadStrategy is specified, it should work fine for the old and new versions of the classes. See MaReadStrategy>>#convertSpecificationsToIdsUsing: to see that it does indeed create depth-specifications for every known version of the class. The variable that does not exist in the old version will simply
Yes? From my analysis it seems the code is missing for this kind of situation. See bellow.
There is no need to "remove" the instance of your domain as it evolves with your class model; the new variables will have nil just like Smalltalk until you populate them and commit.
Can you try again to explain the exact problem you are having? Perhaps a script that reproduces it would improve our mutual clarity?
It is not easy to track the problem (or even reproduce it in another context), but it occures as you told from there in convertSpecificationsToIdsUsing: exactly at (self instVarMapFor: eachDef) in:
[ depths at: { eachDefinition id. eachDefinition version } ifAbsentPut: [ self beNew. (self instVarMapFor: eachDef) ] ] ] ] ]
My class has 4 definitions, and pb comes with id:156, version:1., no prior strategy is present for this version. So from then, throught: self instVarMapFor: eachDef, Magma tries to install a readstrategy for a variable #exerciceAtStart not present in version 1 of the class definition (variable eachDef).
In instVarMapFor:
[ answer := self depthArrayOfSize: aMaClassDefinition namedInstSize. specifiedDepths keysAndValuesDo: [ : eachInstVarName : eachDepth | answer at: (aMaClassDefinition allInstVarNames indexOf: eachInstVarName) put: eachDepth ] ] ]
Here answer=#(0 0 0 0 0 0 0 0 0) (looks ok)
specifiedDepths=Dictionary(#exercice->999 #exerciceAtStart->999 ) (looks ok)
but with eachInstVarName=#exerciceAtStart
(aMaClassDefinition allInstVarNames indexOf: eachInstVarName) is 0
Indeed aMaClassDefinition is definition version 1 where exerciceAtStart instance variable is not present.
Obviously there is a situation there.
The change to the method below prevents the error, but I really don't know if this is the way to do it:
[:eachInstVarName :eachDepth | index := (aMaClassDefinition allInstVarNames indexOf: eachInstVarName). index > 0 ifTrue: [answer at: index put: eachDepth] ]
Hilaire
Thanks for the clarification Hilaire, you have indeed uncovered a bug, and your fix is exactly what is needed.
In addition to your "index>0" guard, in MaReadStrategy>>#forVariableNamed:onAny:readToDepth:, please also remove this check:
(aClass allInstVarNames includes: aString) ifFalse: [ MagmaUserError signal: aString , ' is not an attribute of ' , aClass name ].
This check does not account for the possibility that old versions of classes might define that variable but the not any longer in the newer versions.
Thanks for reporting this just in time to make it into release 40.
BTW, I was able to reproduce the problem easily with the script below. It wasn't too hard once I understood what you were trying to tell me..
Regards, Chris
|session path inst1 rs2| (Smalltalk includesKey: #TestClass) ifTrue: [ (Smalltalk at: #TestClass) removeFromSystem ]. path := 'c:\temp\testReadStrategy1'. MagmaRepositoryController delete: path. MaObject subclass: #TestClass instanceVariableNames: 'oldVar commonVar' classVariableNames: '' poolDictionaries: '' category: 'Testing'. inst1 := (Smalltalk at: #TestClass) new instVarNamed: 'oldVar' put: 'hello' ; instVarNamed: 'commonVar' put: Object new ; yourself. MagmaRepositoryController create: path root: inst1. session := MagmaSession openLocal: path. session inspect. session connectAs: 'test'. "Get rid of the root". Smalltalk garbageCollect. "Now redefine TestClass, remove oldVar, add newVar." MaObject subclass: #TestClass instanceVariableNames: 'commonVar newVar' classVariableNames: '' poolDictionaries: '' category: 'Testing'. rs2 := (MaReadStrategy minimumDepth: 0) forVariableNamed: 'newVar' onAny: (Smalltalk at: #TestClass) readToDepth: 1 ; forVariableNamed: 'oldVar' onAny: (Smalltalk at: #TestClass) readToDepth: 1 ; forVariableNamed: 'commonVar' onAny: (Smalltalk at: #TestClass) readToDepth: 1 ; yourself. session readStrategy: rs2. (Smalltalk at: #TestClass) allInstVarNames do: [ :each | self assert: (session root instVarNamed: each) maIsMutatingProxy not ].
On 7/26/07, Hilaire Fernandes hilaire@ofset.org wrote:
Le Tue, 24 Jul 2007 22:53:58 -0400, Chris Muller a écrit:
Hi Hilaire, sorry for the delayed response; I have just returned from a holiday.
Instances of MaClassDefinition are kept for each version of each class that was ever committed to the repository.
When a ReadStrategy is specified, it should work fine for the old and new versions of the classes. See MaReadStrategy>>#convertSpecificationsToIdsUsing: to see that it does indeed create depth-specifications for every known version of the class. The variable that does not exist in the old version will simply
Yes? From my analysis it seems the code is missing for this kind of situation. See bellow.
There is no need to "remove" the instance of your domain as it evolves with your class model; the new variables will have nil just like Smalltalk until you populate them and commit.
Can you try again to explain the exact problem you are having? Perhaps a script that reproduces it would improve our mutual clarity?
It is not easy to track the problem (or even reproduce it in another context), but it occures as you told from there in convertSpecificationsToIdsUsing: exactly at (self instVarMapFor: eachDef) in:
[ depths at: { eachDefinition id. eachDefinition version } ifAbsentPut: [ self beNew. (self instVarMapFor: eachDef) ] ] ] ] ]
My class has 4 definitions, and pb comes with id:156, version:1., no prior strategy is present for this version. So from then, throught: self instVarMapFor: eachDef, Magma tries to install a readstrategy for a variable #exerciceAtStart not present in version 1 of the class definition (variable eachDef).
In instVarMapFor:
[ answer := self depthArrayOfSize: aMaClassDefinition namedInstSize. specifiedDepths keysAndValuesDo: [ : eachInstVarName : eachDepth | answer at: (aMaClassDefinition allInstVarNames indexOf: eachInstVarName) put: eachDepth ] ] ]
Here answer=#(0 0 0 0 0 0 0 0 0) (looks ok)
specifiedDepths=Dictionary(#exercice->999 #exerciceAtStart->999 ) (looks ok)
but with eachInstVarName=#exerciceAtStart
(aMaClassDefinition allInstVarNames indexOf: eachInstVarName) is 0
Indeed aMaClassDefinition is definition version 1 where exerciceAtStart instance variable is not present.
Obviously there is a situation there.
The change to the method below prevents the error, but I really don't know if this is the way to do it:
[:eachInstVarName :eachDepth | index := (aMaClassDefinition allInstVarNames indexOf: eachInstVarName). index > 0 ifTrue: [answer at: index put: eachDepth] ]
Hilaire
Magma mailing list Magma@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/magma
magma@lists.squeakfoundation.org