Tasks: Components dedicated to sequencing

David Shaffer
Shaffer Consulting

Basics

Without trying to motivate "Tasks" let's just start by building an example: the number guessing game. In this game the computer will select a random number between 1 and 100 and then proceed to repetitively prompt the user for their guess telling them if their guess is too high or too low until they guess the number correctly. Create a subclass of WATask and implement the #go method:
WATask subclass: #GuessingGameTask
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'SCSeasideTutorial'

go
	| number guess |
	number := 100 atRandom.
	guess := (self request: 'Enter your guess') asNumber.
	[guess = number] whileFalse:
		[guess < number
			ifTrue: [self inform: 'Your guess was too low']
			ifFalse: [self inform: 'Your guess was too high'].
		guess := (self request: 'Enter your guess') asNumber].
	self inform: 'You got it!'
Notice that unlike the components we've developed, this class has no renderContentOn: method, just go. Its purpose for existing is to move the user through a sequence of steps. Register it as the root of an application and try it out.

In some sense, tasks are simply components that start their life in a callback. Tasks are indeed components (WATask is a subclass of WAComponent) so all of the facilities available to components, such as call: and answer:, are available to tasks as well. Tasks, however, do not render themselves (don't override renderContentOn: in your tasks), their purpose is simply to sequence through other views.

Exercises

  1. Add a counter to keep track of how many guesses the user made. Be sure to tell them in the end.
  2. After you complete the exercise above, experiment with the effect of the back button on your counter
  3. Experiment with a task which sequences through components of your creation. A simple example would be a task that displays the PersonalInformationView and then displays HelloWorldComponent. If you want to get fancy you could experiment with a login sequence using WALoginDialog. That is, write a task that requires the user to log in before proceeding on to another component.

Isolation

While we're thinking about sequencing I'd like to mention Seaside's isolation support. This is not specific to tasks. General components can take advantage of isolation in their callbacks. If you completed the second exercise above you surely will have noticed that Seaside goes to great lengths to support the back button. If the user presses their back button during a sequence of interactions Seaside effectively "backs up" execution of the method. There are times, however where once a sequence of interactions is complete we do not want to allow the user to back up into them (imagine shopping systems where the user presses back after completing their order, changes something and then completes their order again).

In our guessing game it would be nice if the user couldn't back up and re-submit a guess since this might mess up our count of incorrect guesses (exercise 1 above). The WAComponent>>isloate: method takes a block argument prevents backtracking from outside the block back into the block. Try using the back button in this version of our game:

go
	| number guess |
	number := 100 atRandom.
	self isolate: [guess := (self request: 'Enter your guess') asNumber].
	[guess = number] whileFalse:
		[guess < number
			ifTrue: [self inform: 'Your guess was too low']
			ifFalse: [self inform: 'Your guess was too high'].
		self isolate: [guess := (self request: 'Enter your guess') asNumber]].
	self inform: 'You got it!'
Notice that once you leave an isloated block, you cannot press the back button to back up into that block again. If there were multiple call:'s in the isolate block, the user would be free to move back and forward between those but once they step out of the block they can't move back into it again. Here's an example for you to experiment with:
WATask subclass: #IsolateExample
	instanceVariableNames: ''
	classVariableNames: ''
	poolDictionaries: ''
	category: 'SCSeasideTutorial'

go
	self inform: 'Before isolate'.
	self isolate: 
		[self inform: 'Step 1'.
		self inform: 'Step 2'.
		self inform: 'Step 3'].
	self inform: 'After isolate'.
Register this as an application and experiment with stepping backward (back button) and forward inside, outside and across the isolate block.

Exercises

  1. Study the use of isolate: in WAStoreTask.
  2. Write a simple craps game using a task to sequence through the dice rolls. (You don't have to include betting at first.)

Last modified: Sat Jul 9 14:08:42 EDT 2005