Some days ago I read this in the Digital Mars D programming language newsgroup.
bearophile says:
Automated Resource Blocks, to be able to say things like:
try (BufferedReader br = new BufferedReader(new FileReader(path)) { return br.readLine(); }
instead of:
BufferedReader br = new BufferedReader(new FileReader(path)); try { return br.readLine(); } finally { br.close(); }
and Andrei Alexandrescu (one of the designers behind the language) replies:
They keep on missing the point that the blessed code on the normal path must not take the hit of an extra indentation level.
And he's so right!
In D you'd write it like this:
Disposable disp = new Disposable(); scope(exit) disp.dispose(); // you can use braces too: scope(exit) { } disp.doSomething(); disp.doSomethingElse();
I think this concept is really important. You want the important logic of your method to be always at the same indentation level. The things that, well, you need to do to cleanup things, catch errors, etc., should be on a separate indentation level so that the reader of the code (and that can be you, later!) understands it better.
That's why I prefer this:
void process(Foo someObject) { if (isNotValidForThisFunctionBecauseOfBar(someObject)) return; if (isNotValidForThisFunctionBecauseOfBaz(someObject)) return; // do something else with someObject }
instead of this:
void process(Foo someObject) { if (isValidForThisFunctionBecauseOfBar(someObject)) { if (isValidForThisFunctionBecauseOfBaz(someObject)) { // do something with someObject } } }
Those last indentation levels are distracting. They are forcing you to read on cascade. The first example clearly marks which are the invalid values for the function, or the exceptional values to be handled, while the second one mixes those conditions with the main logic.