[comp.lang.smalltalk] Differencs between Smalltalk/V and Smalltalk/V286

831059l@aucs.UUCP (Langlois) (12/05/88)

	As I mentioned in an earlier posting, I had a few problems getting
a small working simulation in Smalltalk/V to work in Smalltalk/V286. Quite
simply, the same class and methods that worked in Smalltalk/V didn't work
in Smalltalk/V286. The main loop which kept the simulation going in 
Smalltalk/V was in method proceed in class Simulation was as follows:

	proceed
	    [eventQueue isEmpty]
	        whileFalse: [currentEntity := eventQueue removeFirst.
	                     time := currentEntity time.
	                     currentEntity semaphore signal]

Looking at this method you might think that I would have to give up the 
processor at some point in the whileFalse: message to let the entities that
are signalled get a change to execute. That is what I thought also when I 
first implemented the method proceed. I wanted to see what happened if I 
didn't give up the processor so I removed an expression after the last in
the block which sent yield to Processor. In Smalltalk/V it still worked so
I permanently removed the expression because, why send it if it doesn't make
any difference. In Smalltalk/V286 the Processor must be told to yield the
current process for the simulation to work properly, so proceed must be
changed as follows:

	proceed
	    [eventQueue isEmpty]
                 whileFalse: [currentEntity := eventQueue removeFirst.
                              time := currentEntity time.
                              currentEntity semaphore signal.
			      Processor yield]

	Now, if your curious as to how I found this out, well I executed 
the simulation under the new V286 debugger and it worked just fine. I tried
it again without the debugger and it didn't work. When the debugger steps
through the code it must give each process waiting a change to execute,      
taking in account priority and the amount of time spent waiting, every time
it passes control to a process and then interrupts again. In Smalltalk/V
when a semaphore is signalled, the processor must be sent the message yield
to give the process that was signalled a change to take over the processor.
In Smalltalk/V286 this must not be the case, the current process continues
to execute until you tell it to give up the processor.

	The following code also worked fine in Smalltalk/V but caused a
debugger window to pop up with the label "value" not understood:

	probabilityTrue: theProbability
	    theProbability < 0.0 | theProbability > 1.0
	        ifTrue: [self error: 'Probability must be >= 0.0 and <= 1.0']
	        ifFalse: [^self new setProbability: theProbability]

The or "|" causes problem. In Smalltalk/V286, an instance of class False
tries to send the message or: with the argument theProbability which is
then sent the message value which is does not understand because it is
an instance of class Float = 0.5. Smalltalk/V286 routes the shorthand
for "|" through the or: selector while in Smalltalk/V this is not done.
or: is implemented as follows:

	or: aBlock
	    ^aBlock value

I inserted a self halt in this message in Smalltalk/V to try and intercept
but the self halt was never executed. Smalltalk/V either has different order
of evaluation or uses another way to implement "|". By changing the precedence
with parentheses as follows, Smalltalk/V286 can execute the method correctly:
 
	probabilityTrue: theProbability
	    (theProbability < 0.0) | (theProbability > 1.0)
	        ifTrue: [self error: 'Probability must be >= 0.0 and <= 1.0']
	        ifFalse: [^self new setProbability: theProbability]

In Smalltalk/V the evaluation seems to have the two comparisons execute first
and then the result of the second is sent to the first. In Smalltalk/V286
a strict left to right evaluation seems to occur.

	I read the back of the Smalltalk/V286 manual and under the heading
"What is Smalltalk/V 286?" one the items was "Compatibility with Smalltalk/V,
the PC version."
	These are the only differences I have noticed or cared about because
they affected my work. Other than the headache of having to find things like
this, Smalltalk/V 286 is much better than its predecessor.

Steven Langlois     UUCP:     {uunet|watmath|utai|garfield}!dalcs!aucs!831059l
Acadia University   BITNET:   Steven@Acadia
Wolfville, NS       Internet: Steven%Acadia.BITNET@CUNYVM.CUNY.EDU
CANADA  B0P 1X0 


 

831059l@aucs.UUCP (Langlois) (12/06/88)

	As so often is the case, one's first interpretation and solution
for a problem is not correct. As you'll will shortly see, my mistake was 
understandable because of the similarity of the output from my simulation.
But, nevertheless, it was still a mistake. The simulation is Boats 1 from
G. M. Birtwistle's book "Discrete Event Modelling on Simula" (DEMOS). For
those unfamaliar, it is a model of a port system with 2 jetties and 3 tugs.
The boats, Boat 1, Boat 2, and Boat 3, arrive at times 0.0, 1.0, and 9.7
respectively. The actions of a boat are expressed in a smalltalk method
called actions and are as follows:

actions
    self acquire: 1 ofResource: 'JETTIES'.
    self acquire: 2 ofResource: 'TUGS'.
    self hold: 2.0.
    self release: 2 ofResource: 'TUGS'.
    self hold: 13.9.
    self acquire: 1 ofResource: 'TUGS'.
    self hold: 2.0.
    self release: 1 ofResource: 'TUGS'.
    self release: 1 ofResource: 'JETTIES'

When I put the statement Processor yield in the main loop of my simulation
I thought I had solve the problem because with this statement, the    
simulation run as follows:

0.0 Boat 1      schedules Boat 1 at 0.0
0.0 Boat 2      schedules Boat 2 at 1.0
0.0 Boat 3      schedules Boat 3 at 9.7
0.0 Boat 1      seizes 1 of JETTIES
0.0 Boat 1      seizes 2 of TUGS
0.0 Boat 1      holds for 2.0, until 2.0
1.0 Boat 2      seizes 1 of JETTIES
1.0 Boat 2      awaits 2 of TUGS
2.0 Boat 1      releases 2 to TUGS
2.0 Boat 1      holds for 13.9, until 15.9
9.7 Boat 2      seizes 2 of TUGS
9.7 Boat 2      holds for 2.0, until 11.7
11.7 Boat 2     releases 2 to TUGS
11.7 Boat 2     holds for 13.9, until 25.6
---------- etc. -------------

	The first problem occurs when Boat 1 releases 2 TUGS at 2.0. Boat 2
is waiting for 2 of TUGS and when Boat 1 releases 2 it should seize them
and then continue. Instead, Boat 3 arrives and sets the time to 9.7, the 
time when it was scheduled to arrive. From then on, it's a mess and there is
no point of continuing. 
	Now the problem is when the boats are created, they are given the same
priority as the process that was created to execute the selected text. So, 
Boat 3 which has been waiting the longest gets a chance to go before Boat 2
which is waiting for 2 of TUGS. In Smalltalk/V, this wasn't a problem as it
seemed that the selected text wasn't a process or it was created with a lower 
priority than the processes it created. So, in Smalltalk/V the boats where
initialized as follows:

initialize
    eventTime := nil.
    queuedFor := 0.
    waitingSemaphore := Semaphore new.
    processOf := [waitingSemaphore wait.
                  self actions] fork

	In Smalltalk/V286 the boats are given the same priority and hence
the problem. To solve the problem, I changed the creation of a boat as
follows:

initialize
    eventTime := nil.
    queuedFor := 0.
    waitingSemaphore := Semaphore new.
    processOf := [waitingSemaphore wait.
                  self actions] forkAt: CreationPriority

where CreationPriority is a class variable set when a simulation starts to
the priority of the initiating Process + 1. Now I'm not so sure I like the
solution but it works as shown next:

0.0 Boat 1      schedules Boat 1 at 0.0
0.0 Boat 2      schedules Boat 2 at 1.0
0.0 Boat 3      schedules Boat 3 at 9.7
0.0 Boat 1      seizes 1 of JETTIES
0.0 Boat 1      seizes 2 of TUGS
0.0 Boat 1      holds for 2.0, until 2.0
1.0 Boat 2      seizes 1 of JETTIES
1.0 Boat 2      awaits 2 of TUGS
2.0 Boat 1      releases 2 to TUGS
2.0 Boat 2      seizes 2 of TUGS
2.0 Boat 2      holds for 2.0, until 4.0
2.0 Boat 1      holds for 13.9, until 15.9
4.0 Boat 2      releases 2 to TUGS
4.0 Boat 2      holds for 13.9, until 17.9
9.7 Boat 3      awaits 1 of JETTIES
15.9 Boat 1     seizes 1 of TUGS
15.9 Boat 1     holds for 2.0, until 17.9
17.9 Boat 2     seizes 1 of TUGS
17.9 Boat 2     holds for 2.0, until 19.9
17.9 Boat 1     releases 1 to TUGS
17.9 Boat 1     releases 1 to JETTIES
17.9 Boat 3     seizes 1 of JETTIES
17.9 Boat 3     seizes 2 of TUGS
17.9 Boat 3     holds for 2.0, until 19.9
19.9 Boat 2     releases 1 to TUGS
19.9 Boat 2     releases 1 to JETTIES
19.9 Boat 3     releases 2 to TUGS
19.9 Boat 3     holds for 13.9, until 33.8
33.8 Boat 3     seizes 1 of TUGS
33.8 Boat 3     holds for 2.0, until 35.8
35.8 Boat 3     releases 1 to TUGS
35.8 Boat 3     releases 1 to JETTIES

	I realize that multliprocessing was added to Smalltalk/V but a
Goodies disk but I wish the writers of V 286 would have consulted the
creators of the Goodies disk or had of at least inclueded an explanation
of the differences somewhere, on disk or in the manual. The is a file
showing the differences, but as far as differences in multiprocessing
there was nada.

Steven Langlois     UUCP:     {uunet|watmath|utai|garfield}!dalcs!aucs!831059l
Acadia University   BITNET:   Steven@Acadia
Wolfville, NS       Internet: Steven%Acadia.BITNET@CUNYVM.CUNY.EDU
CANADA  B0P 1X0 

831059l@aucs.UUCP (Langlois) (12/10/88)

	Here is an interesting problem. I wanted to create a class Queue
as a subclass of class SortedCollection. An instance of class Queue would
have the sortBlock [ :a : b | a < b ] plus some instance variables such
as observations (to keep track of the number of objects which entered the 
queue), maxLength (the maximum length of the queue), etc. 

	To create a new Queue, I tried the following method:

new
    ^(self sortBlock: [ :a :b | a < b]) initialize

I then execute the following:

|aQueue|
aQueue := Queue new

I very quickly get a walkback, with the label "stack overflow". I tried this
in Smalltalk/V and it worked fine, in Smalltalk/V286, a different story.
I thought using a selector other than new might help so I tried newQueue, but
not luck. I got the same error. 

It took a long time but I finally found the solution to the problem. I defined
class Queue as a variableSubclass of class SortedCollection. That is why (?)
I got the overflow. Just on a whim, I decided to try to define it as a subclass
instead and it worked. In Smalltalk/V, SortedCollection is a variableSubclass
of OrderedCollection. In Smalltalk/V286, it is a subclass of OrderedCollection.
Take a guess at whether it was documented as a change from V to V286!!!

Steven Langlois     UUCP:     {uunet|watmath|utai|garfield}!dalcs!aucs!831059l
Acadia University   BITNET:   Steven@Acadia
Wolfville, NS       Internet: Steven%Acadia.BITNET@CUNYVM.CUNY.EDU
CANADA  B0P 1X0