class C {
void mightFail() { ... }
~C() { doCleanup(); }
};
C c;
c.mightFail();
Anyway, I hate this slide deck so much.
1. The author's point could be made in far fewer slides. As in, like, two slides. I hate presentations that are disrespectful of the audience's time for the sake of being cute.
2. I am generally unimpressed by arguments of the form:
(a) Language X has flaw Y.
(b) Therefore language X is unsuitable for development.
This can be instantiated for every language X for some flaw Y and is not an argument against any language. You need to additionally make the argument:
(c) Y is so serious that it outweighs the considerations in favor of X and against the other languages one might reasonably use.
Of course (c) is an incredibly high bar, which is why most anti-language zealot arguments do not even attempt to make it, and also why most anti-language zealotry is silly.
In order to do (c) in this case, you would have to make the case that writing finally clauses is worse overall than, e.g. debugging memory corruption errors, and writing copy constructors and overloaded assignment operators, and all the other baggage of C++, rather than handwaving them away with "the downsides have been exaggerated".
Which, by the way, is ironically the biggest flaw of this slide deck: the author vastly exaggerates the downsides of finally. try/finally is no worse than checking the result codes of C syscalls, and it is sometimes better. I don't recall the C style of programming stopping Ken Thompson from building great things and I doubt that try/finally is actually what stops Java programmers from building great things.
You seem to have failed to grasp that the slides are arguing for RAII. While admittedly mildly trollish, it disparages java along with C#/ruby/python implicitly in favour of C++ only because C++ has the most 'correct' implementation of RAII.
There is no argument against try/catch/finally, the argument is that the most common usage of try blocks is for dealing with resource management, not actual exceptions in program state. Given exceptions should be used to expression 'exceptional' program states, that is a significant downside to code readability.
Syntactic sugar like using/yield/with blocks improve the signal to noise ratio of try block usage but still rely on programmer acceptance of that idiom. Ideally, the responsibility of cleanup would be moved entirely to the class implementation rather than the consumer. C++ did this with destructors. In a managed world where maybe you don't always want an eager dispose, rather than syntactic sugar in the caller, move it to the signature of the dispose. Something along the lines of
public scoped void Dispose() {
....
}
Alternatively, @Scoped or <Scoped> if you don't want more keywords. The topic is partly to blame but RAII is orthogonal to whether a language is garbage collected or not. It's sad that in an age where PLs are undergoing a sort of renaissance period, mention of C++ causes everyone to circle their respective wagons.
No, you're just oversimplifying his argument. It's not only "hard to remember", it also makes your code overly verbose. That, in turn, degrades its readability, making everyone else spend more time on it and making you, as the author, avoid using the pattern, which leads to writing "prettier", yet unsafe code. Then again, if "hard to remember" is meant as a euphemism for "I know I should write things this way but I really don't want to", then you're completely right.
All in all, he's arguing for RAII, which is impossible in Java and a bunch of other popular languages.
I cannot remember where I saw this (which is a giant problem in itself because I can't remember the details, just that there was a gotcha...) but I read someplace that it is actually pretty easy to introduce disastrous bugs into try/finally blocks. Perhaps it had something to do with managing locks. It could have been the Go guys who said it when talking about why Go doesn't support exceptions, or perhaps it was in multicore literature (perhaps TBB talking about its RAII locking mechanism?). If anybody has any ideas what it is I'm trying to remember here, please comment. If not, well, ignore.
That seems like a pretty serious argument to me. Not only is it a pain in the ass to remember and write that every time you consume a resource that needs to be released somehow, it also introduces all kinds of scoping headaches in Java. If mightFail() returns a value that you want to use after cleanup (i.e. all the time,) then you have to declare the variable to store that value outside of the try {} block.
> [...] then you have to declare the variable to store that value outside of the try {} block
That's kind of the point. The variable will only be assigned a value if mightFail returns normally. The scoping rules make it impossible to accidentally use an uninitialized variable (i.e. a variable whose first assignment was not reached due to an exception).
try {
var result = mightFail();
}
catch {
handleError();
}
finally {
cleanup();
}
print(result) // we don't want to allow this
That's true, the scoping protects you from making that mistake. However, the more common case is this:
try {
var result = mightFail();
}
finally { // let the exception bubble up
cleanup();
}
print(result); // this must be OK, but I can't do it in Java
There are two things I can do to fix the latter case. I can either declare the variable outside the block, adding a silly-looking extra line of code, or I can move the print() within the block, which can be problematic -- it means that if print() were something time-consuming, I would be holding onto the resource during print() for no reason. I think this is a crappy thing to force onto the programmer.
Sure. Another alternative is to pull the try/catch/finally into a separate function that just returns the value. But that's not always convenient, YMMV, etc. Either way, I'd consider it just an occasional annoyance (occasional because frequently print() is quick, or the resource is not expensive or contended).
Honestly, I'm not clear what he's saying, as I don't know D well. It looks like he was saying that SCOPE variables get cleaned up when leaving scope.
Although if doCleanup() also does some additional cleanup, like cleaning up some associated resources that aren't scoped to this block then I think you're still screwed. Maybe someone can clarify if I'm wrong.
Any variables created in the method are cleaned up when the thread leaves the method. I've never heard of clean up being done after execution leaves a try-catch block. Does anyone know the answer to this?
1. The author's point could be made in far fewer slides. As in, like, two slides. I hate presentations that are disrespectful of the audience's time for the sake of being cute.
2. I am generally unimpressed by arguments of the form: (a) Language X has flaw Y. (b) Therefore language X is unsuitable for development. This can be instantiated for every language X for some flaw Y and is not an argument against any language. You need to additionally make the argument: (c) Y is so serious that it outweighs the considerations in favor of X and against the other languages one might reasonably use. Of course (c) is an incredibly high bar, which is why most anti-language zealot arguments do not even attempt to make it, and also why most anti-language zealotry is silly.
In order to do (c) in this case, you would have to make the case that writing finally clauses is worse overall than, e.g. debugging memory corruption errors, and writing copy constructors and overloaded assignment operators, and all the other baggage of C++, rather than handwaving them away with "the downsides have been exaggerated".
Which, by the way, is ironically the biggest flaw of this slide deck: the author vastly exaggerates the downsides of finally. try/finally is no worse than checking the result codes of C syscalls, and it is sometimes better. I don't recall the C style of programming stopping Ken Thompson from building great things and I doubt that try/finally is actually what stops Java programmers from building great things.