About this subject, here is a little reflexion explaining why Notification are not my preferred solution anymore (though I defended it at http://bugs.squeak.org/view.php?id=6755 ). If you remember animated discussions about EndOfStream, then you might say Oh no, not again! However, my opinion has evolved closer to Andreas' one. It still don't find == nil a good solution for generic Stream (though acceptable for character streams). Neither do I reject the idea of catching an EndOfStream : it can be efficient if the event is rare (in other words, if the stream is long, or if there are many wrappers, each testing == nil or atEnd). What I find a big mistake now is to generalize use of an Exception with a default action. I know, this default action is for backward compatibility (answer nil). But let's take an example showing how it can be bad: First load ConnectEndOfStream-M6755-nice.1.cs and RepeatUntil-M6755-nice.1.cs from http://bugs.squeak.org/view.php?id=6755 Then try this: | str sum buffer char | str := '123 456 798' readStream. sum := 0. buffer := WriteStream on: (String new: 16). [char := str next. char isSeparator ifTrue: [buffer isEmpty ifFalse: [sum := sum + buffer contents asNumber. buffer reset]] ifFalse: [buffer nextPut: char]] repeatUntil: EndOfStream. buffer isEmpty ifFalse: [sum := sum + buffer contents.]. ^sum Yes, it just split a string on separators, convert every packet into a number and sum the numbers. The example is silly, don't comment on that. There are plenty other ways to split a String. The problem is that the loop will stop after first number... What's going on? Well, asNumber uses a readStream to perform the conversion, reads past end, and signals an EndOfStream... That is bad... I should have protected the Exception handling with: | str sum buffer char | str := '123 456 798' readStream. sum := 0. buffer := WriteStream on: (String new: 16). [[char := str next. char isSeparator ifTrue: [buffer isEmpty ifFalse: [sum := sum + buffer contents asNumber. buffer reset]] ifFalse: [buffer nextPut: char]] repeat] on: EndOfStream do: [:exc | exc receiver == str ifTrue: [exc return] ifFalse: [exc pass]]. buffer isEmpty ifFalse: [sum := sum + buffer contents.]. ^sum Oh yes, easy. But imagine now that str is a wrapper on a FileStream... (for example an InflateStream). Exception handling soon becomes hard to write, because you might have to walk up the Context stack... There are better examples where I want Exceptions, so I'd like the choice to be in programmers hands. - 1) Raising an EndOfStream Exception (and not a Notification as I suggested) should be optional - 2) The Exception should not have a default action. The simple thing to do is to add an endOfStreamAction instanceVariable to Stream or ReadStream. If a read past end is attempted, then ^endOfStreamAction value. nil value = nil, so letting this inst var uninitialized will lead to backward compatibility (at minimal cost concerning efficieny!). filling the inst var with a block comes to mind immediately, and among natural choice is: Stream>>willSignalEndOfStream self endOfStreamAction: [EndOfStream signal] There might be more work for Stream wrappers, but that sounds a cheap and efficient idea to reconcile both worlds. What will protect above code example from an internal low level EndOfStream? Nothing, but the fact that programmers using explicitely #willSignalEndOfStream will know what they do! Either they will protect with a handling block, or advertise enough that the code might generate spurious EndOfStream on malformed inputs... Of course, I must remind: use Exception handling pattern but don't abuse. Programming with these deserve great care! Cheers Nicolas