Thread overview
auto BufferedFile keeps file locked
Apr 21, 2006
Lionello Lunesu
Apr 21, 2006
Ben Hinkle
Apr 21, 2006
kris
April 21, 2006
Hi,

Been playing around with the stream classes in Phobos some more and I've noticed the following:

#void bla( char[] fn ) {
#  auto BufferedFile bf = new BufferedFile;
#  bf.open(fn);
#}

After calling the function "bla", the opened file remains locked. Adding "bf.close" at the end of the function correctly closes the file and does not keep the file locked. Using "File" instead of "BufferedFile" also solves the problem.

After thinking about it for half an hour I finally got it: the BufferedFile, which had a reference to a File instance, got destructed like it should but the File's not being collected together with the BufferedFile.

It seems the File instance inside BufferedFile should be linked somehow to the BufferedFile instance.

Would adding a destructor to BufferedFile solve the problem?

#class BufferedFile: BufferedStream {
#
#  // opens file for reading
#  this() { super(new File()); }
#  ~this() { close(); }
...

L.

PS. Who else thinks it should be "BufferFile" (and not "BufferedFile"; (analogous to "FilterStream" and not "FilteredStream")?
April 21, 2006
"Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:e2akhb$2au3$1@digitaldaemon.com...
> Hi,
>
> Been playing around with the stream classes in Phobos some more and I've noticed the following:
>
> #void bla( char[] fn ) {
> #  auto BufferedFile bf = new BufferedFile;
> #  bf.open(fn);
> #}
>
> After calling the function "bla", the opened file remains locked. Adding "bf.close" at the end of the function correctly closes the file and does not keep the file locked. Using "File" instead of "BufferedFile" also solves the problem.
>
> After thinking about it for half an hour I finally got it: the BufferedFile, which had a reference to a File instance, got destructed like it should but the File's not being collected together with the BufferedFile.
>
> It seems the File instance inside BufferedFile should be linked somehow to the BufferedFile instance.
>
> Would adding a destructor to BufferedFile solve the problem?
>
> #class BufferedFile: BufferedStream {
> #
> #  // opens file for reading
> #  this() { super(new File()); }
> #  ~this() { close(); }
> ...

An object's destructor cannot refer to any other gc-managed resource. In particular the BufferedFile's destructor cannot close the associated File. See the help section about garbage collection for more info. With the current language design there is no way to have a 'auto' class clean up more than just itself. For example by the time the BufferedFile destructor runs the buffer used to hold the data of the BufferedFile might be gone and unreachable.

> L.
>
> PS. Who else thinks it should be "BufferFile" (and not "BufferedFile"; (analogous to "FilterStream" and not "FilteredStream")?


April 21, 2006
Ben Hinkle wrote:
> "Lionello Lunesu" <lio@lunesu.remove.com> wrote in message news:e2akhb$2au3$1@digitaldaemon.com...
> 
>>Hi,
>>
>>Been playing around with the stream classes in Phobos some more and I've noticed the following:
>>
>>#void bla( char[] fn ) {
>>#  auto BufferedFile bf = new BufferedFile;
>>#  bf.open(fn);
>>#}
>>
>>After calling the function "bla", the opened file remains locked. Adding "bf.close" at the end of the function correctly closes the file and does not keep the file locked. Using "File" instead of "BufferedFile" also solves the problem.
>>
>>After thinking about it for half an hour I finally got it: the BufferedFile, which had a reference to a File instance, got destructed like it should but the File's not being collected together with the BufferedFile.
>>
>>It seems the File instance inside BufferedFile should be linked somehow to the BufferedFile instance.
>>
>>Would adding a destructor to BufferedFile solve the problem?
>>
>>#class BufferedFile: BufferedStream {
>>#
>>#  // opens file for reading
>>#  this() { super(new File()); }
>>#  ~this() { close(); }
>>...
> 
> 
> An object's destructor cannot refer to any other gc-managed resource. In particular the BufferedFile's destructor cannot close the associated File. See the help section about garbage collection for more info. With the current language design there is no way to have a 'auto' class clean up more than just itself. For example by the time the BufferedFile destructor runs the buffer used to hold the data of the BufferedFile might be gone and unreachable.
> 
> 
>>L.
>>
>>PS. Who else thinks it should be "BufferFile" (and not "BufferedFile"; (analogous to "FilterStream" and not "FilteredStream")? 
> 
> 
> 


This is exactly the kind of problem discussed in the "auto classes and finalizers" thread. Due to the "unspecified" state (of references) when a dtor is called by the GC, one cannot, as a general rule use a dtor to clean up -- if you 'forget' to delete or raii it, the GC will collect the class and the example dtor (above) will currently GPF.

This situation encourages the use of dispose()/close() instead, which is arguably the wrong approach. The Ares runtime library now has support for controlling the behaviour of collections upon dtors.