Change Set File Out problem Problem 1

Eric Arseneau earseneau at exobox.com
Wed Nov 15 04:42:26 UTC 2000


This mail is quite long and involved, so read at your own peril ;-)

It seems that there are a couple of problems with change sets, new classes,
class changes, and filing out.

Problem 1:
---------------
- Create a new change set, direct changes to it
- Create a new class with 'a b c' as inst vars
- File out the change set
- Delete new class
- Delete change set, or delete class changes from change set
- Create new change set, direct changes to it
- File in the previous file out
- remove any inst var from new class
- file out class

And presto, the instance variables will be there in the file out.  This is
NOT good.  I am using a 2.8 image and therefore do not know if the problem
exists in 2.9 or later.  Even if it does not, we need to find a fix for it
in 2.8.  Oh as a side note, if you do the first def of the class as no inst
vars then file out then in and add inst vars, the inst vars come out
backwards !!!

Here is what I have found as the source of the problem.  The following
method gets called from change sets in order to file out:

ChangeSet>>fatDefForClass: class

	| newDef oldDef oldStrm newStrm outStrm oldVars newVars addedVars |
	newDef _ class definition.
	oldDef _ (self changeRecorderFor: class) priorDefinition.
	oldDef ifNil: [^ newDef].
	oldDef = newDef ifTrue: [^ newDef].

	oldStrm _ ReadStream on: oldDef.
	newStrm _ ReadStream on: newDef.
	outStrm _ WriteStream on: (String new: newDef size * 2).

	"Merge inst vars from old and new defs..."
	oldStrm upToAll: 'instanceVariableNames:'; upTo: $'.
	outStrm nextPutAll: (newStrm upToAll: 'instanceVariableNames:');
nextPutAll: 'instanceVariableNames:';
		nextPutAll: (newStrm upTo: $'); nextPut: $'.
	oldVars _ (oldStrm upTo: $') findTokens: Character separators.
	newVars _ (newStrm upTo: $') findTokens: Character separators.
	addedVars _ oldVars asSet addAll: newVars; removeAll: oldVars;
asOrderedCollection.
	oldVars , addedVars do: [:var | outStrm nextPutAll: var; space].
	outStrm nextPut: $'.

	class isMeta ifFalse:
		["Merge class vars from old and new defs..."
		oldStrm upToAll: 'classVariableNames:'; upTo: $'.
		outStrm nextPutAll: (newStrm upToAll:
'classVariableNames:'); nextPutAll: 'classVariableNames:';
			nextPutAll: (newStrm upTo: $'); nextPut: $'.
		oldVars _ (oldStrm upTo: $') findTokens: Character
separators.
		newVars _ (newStrm upTo: $') findTokens: Character
separators.
		addedVars _ oldVars asSet addAll: newVars; removeAll:
oldVars; asOrderedCollection.
		oldVars , addedVars do: [:var | outStrm nextPutAll: var;
space].
		outStrm nextPut: $'].

	outStrm nextPutAll: newStrm upToEnd.
	^ outStrm contents

This method basically looks in the change set record to see if there is an
old definition to the class in question.  If there is, then it actually
merges the old and the new definition into one and files that out.  This
means that there is no way to get rid of instance variables.  Why is this
done ?  And how can it be fixed to not have this problem.

Here is some test code you can run to see this happen in real time:

| doBlock changeSetName className otherFilename |
changeSetName := 'dummy-test'.
className := #DummyClass.
(Smalltalk includesKey: className) ifTrue: [
	self error: 'Cannot proceed with test, there is already a test class
named: ', className printString].
(ChangeSorter changeSetNamed: changeSetName) isNil ifFalse: [
	self error: 'Cannot proceed with test, there is already a test
change set named: ',
		changeSetName printString].
doBlock := [:classDefBlock |
	| oldChanges filename file changeSet newClass |
	oldChanges := Smalltalk changes.
	Smalltalk newChanges: (
		changeSet := ChangeSet new initialize name: changeSetName).
	newClass := classDefBlock value.
	filename := FileDirectory default nextNameFor: changeSet
nameForFileOut extension: 'cs'.
	changeSet fileOut.
	file := FileStream readOnlyFileNamed: filename.
	Workspace new
		contents: file contents;
		openLabel: filename.
	file close.
	newClass removeFromSystem.
	Smalltalk newChanges: oldChanges.
	ChangeSorter removeChangeSet: changeSet.
	filename].

otherFilename := doBlock value: [
		"Define class from fresh"
	Object subclass: className
		instanceVariableNames: ''
		classVariableNames: ''
		poolDictionaries: ''
		category: 'Exo-Resource Management'].
otherFilename := doBlock value: [
		"File in a definition of class, then change def by adding
inst vars"
	(FileStream readOnlyFileNamed: otherFilename) fileIn.
	Object subclass: className
		instanceVariableNames: 'a b c'
		classVariableNames: ''
		poolDictionaries: ''
		category: 'Exo-Resource Management'].
doBlock value: [
		"File in a definition of class, then change def by removing
inst vars"
	(FileStream readOnlyFileNamed: otherFilename) fileIn.
	Object subclass: className
		instanceVariableNames: 'a '
		classVariableNames: ''
		poolDictionaries: ''
		category: 'Exo-Resource Management'].






More information about the Squeak-dev mailing list