Hire and Fire

Tagged:

Whenever I write something like the following, I feel homesick for ruby, where I never have to close files by myself.

 |stream|
 stream := FileStream fopen: 'registry.dump' mode: #write.
 [ ObjectDumper dump: registry to: stream ] ensure: [ stream close ]

Would anybody else beside me consider the following (fancily named) pattern useful?

 Object [ 
   hire: aBlock fire: cleanup [ 
     ^ [ aBlock value: self ] ensure: [ cleanup cull: self ]
   ]
 ]

It could be used for implementing a message #hire: on Stream:

 Stream [
   hire: aBlock [ 
     ^ self hire: aBlock fire: [ self close ]
   ]
 ]

and the introductory example would become

 ( FileStream fopen: 'registry.dump' mode: #write )
   hire: [ :s | ObjectDumper dump: registry to: s ]

Just wondering... and let me know if you know of a better name.

aFilename temporaryFileStreamDo: [:fs | ...]

or even

aFilename fileStreamDo: [:fs | ...]

If I remember correctly, Blaine Buxton had blogged about this before.

Hi,

The manual way of closing of files has always bugged me about the different smalltalk systems. In some smalltalks you get an error and when you dismiss the debugger the file is still open so of course the next time you try to open it it fails... I concur that it's annoying...

What is the naming notion behind the method #hire:fire:? It seems an odd method name pair...

A question is what is the scope of the work to be done on the open file. Sometimes you just want a couple of group of operations that are all contained within a block so the operational scope is clearly that block... nice for many common cases.

It's the longer term access to the file object that isn't contained within a single simple block that I'm wondering about too. Maybe a way of attaching a block to the file itself so it knows about being closed and under what conditions to do so automatically (such as being reopened).

It's an interesting problem to consider. How best to handle files?

All the best,

Peter William Lount
peter@smalltalk.org
http:/www.Smalltalk.org

... and I was playing around with definr.com looking for a nice short pair of words.

The use case for this is exactly what you're saying:
Sometimes you just want a couple of group of operations that are all contained within a block so the operational scope is clearly that block

This pattern occurs often enough so I want to get it out of sight. Dealing with database connections is another similar situation. Using Paolo's suggestion (look below), it would look like

[ :db | db runSQL: 'select 3+4' ] use: DBConnection new

with

DBConnection [
   useDuring: aBlock [
     [ aBlock value: self ] ensure: [ self close ]
   ]
 ]

It would be also quite nice to use when "patching" data, where error handling might be important:
[ :tx | tx runSQL: 'update this'; runSQL: 'delete from that'; ...] use: Transaction new
and accordingly

Transaction [
   useDuring: aBlock [
     [ aBlock value: self ] on: DBError do: [ ^self rollback ].
     self commit
   ]
 ]

It's definitely not a silver bullet for every possible use case, but it's a pattern coming in handy especially during "scripting" jobs, i.e. small-scale, one-off thingies.

The motivation behind this is the ruby idiom where you pass a block into e.g. File.open and the open implementation takes care of closing the file again for you. Very easy on the brain .-)

Pharo has FileStream>>#fileNamed:do: and friends.

but I know of

'registry.dump' asFile withWriteStreamDo: [ :s |
    ObjectDumper dump: #foo to: s]

-)

RTFM :-)

And look, it even has a brother withReadStreamDo:, what I could be using the in the counterpart of my method.

Thanks!

For your idiom, I'd do BlockClosure>>#use: and Object>>#useDuring:

[ :s | ObjectDumper dump: #foo to: s ]
    use: 'registry.dump' asFile writeStream

BlockClosure>>use: anObject
    ^anObject useDuring: self

Object>>useDuring: aBlock
    ^aBlock value: self

Stream>>useDuring: aBlock
    ^[ aBlock value: self ] ensure: [ self close ]

but I'm not sure I really like it, I prefer specialized messages like #withWriteStreamDo:.

and it has the added bonus of allowing exception handling in useDuring, too. That's good.

User login