Yes, you can do this with try/finally. But if you have an object that has an open file as a member, then you open the file in the constructor, and then use the open file in the member methods, and then... what? You may have a scope that you are exiting where that object becomes irrelevant, but it may be several layers away. Having to close that object's handle in a finally in that scope seems likely to be forgotten at least some of the time.
That "scope that you are exiting ... several layers away" is where you put the try/finally.
If an object has resources to dispose of (such as an open file), it should implement (to use C# as an example – it looks similar in Python and Java) the IDisposable interface, which allows you to do either:
using (MyFileWrapperObject obj = ...) {
foo();
bar();
...
}
Or to take a Python example from what I'm working on right now:
with open("something.json") as f:
data = json.load(f)
The file will automatically be closed at the end of the "with" block. Just like in C#, this feature can be used for any kind of resource, not just files.
> That "scope that you are exiting ... several layers away" is where you put the try/finally.
Yes, I know that it's where you're supposed to put the try/finally... if you remember. Each time. And if you move the action in the finally clause if the variable changes scope or lifetime.
Destructors are considerably cleaner than this approach. You just put the close in the destructor, and let it do its job.