[squeak-dev] handling Notification safely

Chris Muller asqueaker at gmail.com
Tue Oct 11 02:58:41 UTC 2011


It appears that handling Notification can result in an unexpectedly
brittle situation if the code also ever uses
String>>#displayProgressFrom:to:during:.

Background:  I'm using use a CommandLineProcessor class to run batch
jobs in headless mode.  I use a high-level handler on Notification and
Warning to write any messages to stdout thusly:

	| stdOut stdErr |
	self ensureStartedUp.
	stdOut := StandardFileStream stdout.
	stdErr := StandardFileStream stderr.
	[ aBlock valueWithAllArguments: self args ]
		on: Notification , Warning
		do:
			[ : noti | stdOut
				 nextPutAll: DateAndTime now asString ;
				 space ;
				 nextPutAll: noti description ;
				 perform: MultiByteFileStream lineEndDefault.
			noti resume ]

However, some of the code run by aBlock valueWithAllArguments: ends up
doing its work under Squeak's standard progress-notifying facility,
String>>#displayProgressFrom:to:during:.  The result is that
explicitly handling Notification implicitly handles
ProgressInitiationExceptions, and therefore
ProgressInitiationException>>#defaultAction does not run, which means
that the code being monitored does not run.  Silently.  Yikes!

Behold with an example:

| receivedSignal resumed |
receivedSignal := resumed := false.
[ "client-code puts up progress, and signals some notications"
| count | count := 0.
 'doing something'
	displayProgressFrom: 0 to: 10 during:
		[ : bar |
		10 timesRepeat:
			[ bar value: (count:=count+1).
			(Delay forMilliseconds: 500) wait.
			Notification signal: 'message'.
			resumed:=true ] ] ]
	on: Notification
	do:
		[ : noti | receivedSignal:=true.
		noti resume ].
self
	assert: receivedSignal ;
	assert: resumed

So, I suppose we need to handle ProgressInitiationException
separately, and call the #defaultAction.

| receivedSignal resumed |
receivedSignal := resumed := false.
[ "client-code puts up progress, and signals some notications"
| count | count := 0.
 'doing something'
	displayProgressFrom: 0 to: 10 during:
		[ : bar |
		10 timesRepeat:
			[ bar value: (count:=count+1).
			(Delay forMilliseconds: 500) wait.
			Notification signal: 'message'.
			resumed:=true ] ] ]
+	on: ProgressInitiationException
+	do: [ : prog | prog defaultAction ]
	on: Notification, Warning
	do:
		[ : noti | receivedSignal:=true.
		noti resume ].
self
	assert: receivedSignal ;
	assert: resumed

This strikes me as a remarkably fierce penalty for something this
non-obvious.  Should it be improved?

 - Chris



More information about the Squeak-dev mailing list