In code that looks like
open a file process the file close the fileI often forget to close the file. I guess I just get so excited about what's in the middle.
In VW Smalltalk, I discipline myself to use #valueNowOrOnUnwindDo: whenever I use files. So now I make the mistake only when I'm hacking.
In Smalltalk/V, I had a method on String and Filename that accepted a block, passed the open file into it, and closed the file outside. Something like:
'input.txt' processFile: [ :f | self processInput: f]In C, I used a keyboard macro that generated the open and the close at the same time, and edited the middle. Disciplined myself to use it. -- RonJeffries ItsNotAboutDiscipline.
That looks just like the with-open-file and related macros of Common Lisp. -- JohnDouglasPorter
In RubyLanguage, File#open can be called with a block, in which case it does the same thing.
Yes; and it's not just files, it's graphic contexts, bitmaps and other GUI stuff; any resource which the O/S has an interest in.
In C++, the ResourceAcquisitionIsInitialization idiom puts the close into the file's destructor, so it gets called as the stack unwinds. This is similar to the idioms you suggest. My impression is Java programmers have a lot of problems with this kind of thing. People are surprised that they can get resource leaks despite having garbage collection.
If you have finalization, it can be worth sticking assert(!isOpen()) in the File one to catch the mistake. -- DaveHarris
If you have finalization, why would it not be preferable to simply have the file close automagically?
Because finalization is not guaranteed to happen, and if it happens, there is no guarantee as to when it happens.
In C# there is a "using" block for similar functionality - if you call the constructor for a class in the block opening, its IDisposable.Dispose() is implicitly called at the end of the block. Unfortunately, not supported in other DotNet languages like VisualBasicDotNet. However, now that C# and VB have better support for closure-like functionality with implicit delegates and anonymous methods, one could do it in the more functional approach.
This is one of the big advantages of using IO::File (in PerlLanguage) rather than the old-fashioned TypeGlob?-as-FileHandle?. IO::File objects auto-close when they go bye-bye. -- JohnDouglasPorter
Just to clarify: this is the behaviour as soon as you declare a lexical scalar for the file handle (as opposed to the typeglob), you don't have to use IO::File explicitly.
open(my $fh, "<", $file) or die;-- JpL
On a related note:
As stated above, in C++, with ResourceAcquisitionIsInitialization, the file will close as part of a destructor. If the file is open for writing, the close will flush. If you don't flush first manually, errors can occur during close (like ENOSPC:"out of disk space", etc.) and you will never know it - Destructors don't throw. Therefore, you should flush before close.
see BewareOfExceptionsInTheDestructor
-- DirckBlaskey
If it is likely to be a small file, then perhaps read the result into memory in a small block and then process it. SeparateIoFromCalculation.
If it is a large file, then perhaps consider random-access, as-needed reads within a tight open-close block. In other words, treat it more like a database. This works best in situations where the processing or wait-time between reads is long.
I recently forgot to do this in some of my ObjectiveCaml code... mainly because I thought the GC would do it for me. Apparently not, even though it seems it would be nigh-trivial:
let new_open_in x = let fd = open_in x in Gc.finalize close_in fd; fd ;;Anyone know why this might be?