www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - auto BufferedFile keeps file locked

reply Lionello Lunesu <lio lunesu.remove.com> writes:
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")?
Apr 21 2006
parent reply "Ben Hinkle" <bhinkle mathworks.com> writes:
"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")? 

Apr 21 2006
parent kris <foo bar.com> writes:
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.
Apr 21 2006