" Note that this subclass is of the system Array class. To enable correct allocation, it must be declared as a variableSubclass. For more details on why, see the GNU Smalltalk User's Guide." Array variableSubclass: #TwoDArray instanceVariableNames: 'rows cols ' classVariableNames: '' poolDictionaries: '' ! !TwoDArray class methods ! " Note that the constructor here is a class method rather than an instance method. This makes sense, because an object cannot really construct itself. However, a class method cannot initialize instance variables, so to do any initialization, we must call an initialization instance method on the new object" " In this case, we are calculating how large the underlying array must be, then constructing the superclass array accordingly. Finally we initialize the rows and columns using the instance method" rows: oneInt cols: twoInt "initialize a new two-d array" | asize | asize := oneInt * twoInt. ^(super new: asize) giverows: oneInt givecols: twoInt! ! !TwoDArray methods ! "return new TwoDArray containing sum of receiver an aTwoDArray. aTwoDArray must be compatible with receiver. Note that this is overloading the '+' operator" + aTwoDArray | newArr | (self compWith: aTwoDArray) ifFalse: [^self error: 'Arrays not compatible'] ifTrue: [ newArr := TwoDArray rows: rows cols: cols. 1 to: rows do: [ :i | 1 to: cols do: [ :j | newArr atrow: i atcol: j put: ((self atrow: i atcol: j) + (aTwoDArray atrow: i atcol: j)) ] ]. ^newArr ]! atrow: oneInt atcol: twoInt "return value in appr. row and col" | index | index :=((oneInt - 1) * (cols)) + twoInt. ^self at: index.! atrow: oneInt atcol: twoInt put: anObject | index | index := (cols * (oneInt - 1)) + twoInt. ^self at: index put: anObject! compWith: aTwoDArray (self class = aTwoDArray class) ifFalse: [^false] ifTrue: [ (( rows = aTwoDArray getrows) and: [ cols = aTwoDArray getcols] ) ifFalse: [^false] ifTrue: [^true]].! getcols "answer number of columns in receiver" ^cols! getrows "answer number of rows in receiver" ^rows! "This method should be private, since it is used to initialize rows and cols and should only be called from the constructor " giverows: oneInt givecols: twoInt rows := oneInt. cols := twoInt.! printString | aStream temp| aStream := WriteStream on: String new. aStream nl. 1 to: rows do: [ :i | 1 to: cols do: [ :j | temp := self atrow: i atcol: j. (temp = nil) ifTrue: [aStream nextPutAll: 'nil'] ifFalse: [ aStream nextPutAll: temp printString]. aStream space ]. aStream nl ]. ^(aStream contents)! !