Garbage collection with Automatic Resource Management in Java 7
javawithswaranga.blogspot.com
javawithswaranga.blogspot.com
InputStream in = null;
try
{
in = new FileInputStream(new File("test.txt"));
//do stuff with in
}
catch(IOException ie)
{
//SOPs
}
finally
{
try
{
if(in != null)
{
in.close();
}
}
catch(IOException ioe)
{
//can't do anything about it
}
}
This merely proves your point! :-)This is just horrible. What braindead system forces you to check exceptions on closing a file handle? If everything failed silently and just produced 'null', the code would look like:
InputStream in = new FileInputStream(new File("test.txt"));
if (in) {
...dostuff...
in.close();
}
Now, that you can grasp with one glance. I'll trade the ability to write something like that with having to use malloc()/free() any day.How is the user supposed to figure out what went wrong with the program if the program can't even convey to the user what went wrong?
Complex problems have lots of simple wrong answers.
(Your "solution" also suggests nothing about how "in.close()" is going to get called if "...dostuff..." itself throws an exception.)
//define it like this: def using[T <: {def close(): Unit }, S](obj: T) (operation: T => S) = { val result = operation(obj) obj.close() result }
//use it like this: val writer = new FunkyWriter using(writer) { writer.write("outputting some data") }
ARM was therefore possible in Scala before the Closable interface was even added to the Java libs.
lombok's @Cleanup will close anything, interface or not.
InputStream in;
try(in = new FileInputStream()){
...
} catch (...){
...
}
Now there are no new lexical scoping rules to understand. A lesser point is that I find the try(x = e) syntax ugly. It reminds me of the C-ism where a variable is set and tested in an if statement. if (x = getline()){
...
}
Control flow and side effects should not be mixed, IMO.And when you introduce that, you have a problem of dealing with the difference between references to these inline objects: possibly on the stack or the heap, free-standing or embedded. If a reference escapes and outlives the lifetime of the object, you've created a potential dangling pointer, whereas in the normal Java or C# implementation you have at worst a semantic problem of having leaked a reference to a "closed" or disposed object. The GC won't collect it, but any operations on it will and should fail.
If you try and deal with this in the C++ way, you'll end up with far more confusion over objects passed around by reference, and objects passed around by value. Instead of the mechanism of passing being encoded by the type, it would be part of the control flow, and it would be easy to get into situations where you're working with a reference to a copy that was passed by value, and think you have a reference to the original; this is already a problem in C# to the degree that it is not recommended to create mutable value types.
TL;DR: what you suggest would create far more problems than it solves.