Can't you just implement finally in "userspace"? In Perl, you can implement it with object destruction -- you make an instance of an object whose destructor does the cleanup you want, and when it goes out of scope (exception thrown, return, etc.), the cleanup code is run.
It's extremely common to write code like:
sub work_in_tmpdir(&) {
my $cwd = cwd;
my $guard = guard { chdir $cwd };
chdir mktmp;
$_[0]->();
}
Then you can safely work in a temporary directory:
No language feature or bug tracker rant-fest required! And, I'm pretty sure that you can abuse destructors in PHP to get exactly the same result. (In Perl, that "guard" function from the Guard module is implemented something like: class Foo { has 'cleanup' => (is => 'ro', isa => CodeRef ); sub DESTROY { $self->cleanup->() } }; sub guard(&){ return Foo->new( cleanup => $_[0] ) })
(+) Also, don't cut-n-paste this code into your apps. It misses special cases. use Try::Tiny, TryCatch, etc. from the CPAN.
That's a neat example, but you're abusing Perl's syntax for that syntactic-sugar, and it doesn't work like that in PHP (e.g. parens cannot be omitted, and does this code even compile with "use strict"?)
It compiles with "use strict", and it's not abuse.
The reason you can't compile it is because guard is not defined, nor are cwd, cleanup, and the other placeholder functions I used. When you are relying on the parser to add parens for you (and let you omit "sub"), you have to have the function in scope. Compare:
If you think that's "abusing" Perl 5 syntax for a useful effect, you should start reading up on Perl 6. Though you probably shouldn't if you have a weak heart.
Yeah, I know. But working on a wood statue with a humble knife should not be an excuse for the chainsaw guy to call you a dumb bastard for not be doing the statue with the chainsaw, "like proper men should do". Yes, the quoted phrase was actually heard on my office. Go figure...
( ...and I don't have anything against ruby. I'm learning rails. www.railsforzombies.com is great. In fact, my php is made on cakephp and lithium, which are pretty similar to rails... )
Exceptions are control flow and nothing more. Any try/catch block could be rewritten with if/else checks on various error flags, assuming such flags are exposed. See C. Exceptions are just a clean way to write error handling and stack unwinding code without large amounts of if/else and return statements. Saying "finally" isn't necessary is like saying "foreach" isn't necessary when you have "while".
"Any try/catch block could be rewritten with if/else checks on various error flags"
Well, yes and no. Correctly writing your if flags to be polymorphic on the type of the exceptions is certainly possible but you're getting into the domain of things that a compiler really ought to be doing for you.
I've successfully made use of polymorphic exceptions, but I will freely concede I seem to be in the minority. Also I love having them being objects because then I also load the logic into them for presentation both to the human user and the developer which turns out to be really useful but also apparently a minority idea. Adding that to your if/else blocks would be insane.
Frankly, exceptions are badly underutilized, but one could say that about quite a lot of OO concepts, really. Many people understand the surface forms but manage to miss the point entirely. If that's all you've ever seen for exception handling I can understand why you wouldn't think it's very useful.
In this case, do_something_finally() will never be called.
try {
throw new IOException("bad");
} catch ( NotAnIOException e) {
System.out.println("This is something I expected to happen.");
}
do_something_finally();
With a finally block, it would be, and the IOException would then be bubbled up to the caller. Without finally, you need to do this:
try {
throw new IOException("bad");
} catch ( NotAnIOException e) {
System.out.println("This is something I expected to happen.");
} catch (Exception e) {
do_something_finally();
throw e;
}
do_something_finally();
No, you're right. The code in the above example behaves differently than the finally version in the case where UNLOCK TABLE throws something.
This seems to be an example where the hack is preferred over the correct solution. The hack in this case is going to work almost all of the time.
I fail to see how throwing up an example of a hack is a good way to argue for or against a language feature. Generally speaking if the language is decent enough there is always a way to hack in some new semantics yourself (I'm looking at you, anonymous inner Java classes for closures), but language features allow you to compose and represent those semantics more elegantly. So, the argument shouldn't be "can we do this already with a hack" it should be "is this hack common enough that we should fix it."
The point the author is making is almost self-evidentally against his own conclusion: here's a common pattern that is broken, so we should not include this as a language feature???
> The point of finally is that it's always, always, always executed.
Except when it's not. If you design a large system with the assumption that finally blocks always execute, you could end up with some data integrity issues when you get a power outage, an exception in your finally clause, a hung machine, or any other number of errors that a finally clause does nothing to address.
The finally clause is very useful, but to say that it will always (x3!) execute is somewhat perilous.
According to the linked article, the second one will not run do_something_finall() since it is after the return statement. The second one however will...
Note, this does seem to be the case for javascript:
Your first example will do_something_finally() before returning y and exiting the try-scope and method (unless an error has occurred). Your second example will return y without invoking do_something finally() (unless an error has occurred).
If an error occurs before "return y", both will behave equally.
Basically the finally-clause is guaranteed to be run always. This means that you can put your resource-cleanup logic there and know it will be invoked if errors occur or not, without the need to duplicate that logic within the catch-block.
Especially when the catch-block is set to rethrow (or just outright omitted) this saves the programmer a lot of time, code-duplication and makes the code more readable.
The reasons given for omitting it by the PHP team is factually incorrect and shows that they clearly don't understand how the feature is supposed to work. With that hindsight, it would be interesting to see how it would have been implemented if they had gone forward adding it instead of saying "no". It could have become a highly fascinating monster.
A programming language is a tool and its syntax is its UI. PHP community doesn't get this. They never have. Just because you can empirically prove that a language doesn't need a feature, it doesn't mean you shouldn't add it if it's obvious that most developers would _enjoy_ using it.
Just like with C++ (which also doesn't have finally) you can use RAII techniques with PHP. Object destructors will get called when your object goes out of scope. I use this to clean up resources (mainly rollback transations) in the case of exceptions.
In fact, now with PHP 5.3 and closures one could emulate finally quite easily: just create an object that runs the closure on destruction and it will be called at the end of the block.
Finally would still, however, be a welcome addition to the language.
The example is the wrong case. Unless you are using MyISAM tables (hint: 90%+ of the time you shouldn't), there's rarely a situation to LOCK TABLES as described.
Using transactions would make more sense:
try {
mysql_query("START TRANSACTION");
// ... do lots of queries here
mysql_query("COMMIT");
} catch(Exception $e) {
mysql_query("ROLLBACK");
}
You left out the code where you acquire the database connection and need to release it before returning as well as propagate the success or failure of the operation.
I don't think 'finally' is mandatory, I have never missed it, sure it may be syntactic sugar 1% of the time, but are we developing for the rare cases now?
One of the notes on the report is someone who did try to dig up the discussion and couldn't find it, only a bunch of people saying without reasons "we do not need finally". It seems polite to me for someone who knows when/where said discussion was to link to it.
So if I read that right, you don't need finally because you can unlock mysql tables when catching the exception? That's brilliant. Clearly as far as the PHP team is concerned, there is no other use for PHP than using it with MySQL.
The person who submitted the bug included an example of finally with MySQL, and the PHP guy was holding to that theme so that his response would be as clear as possible. So really, you should be blaming some random guy on the Internet for having no other use for PHP than using it with MySQL, which is more than likely true.
Syntactic sugar would be the right term for this, I guess. I think everyone who has dealt in languages not having Try-Finally can recall a case or two where it would've felt smooth and tidy to have access to Finally - but never, ever a case where they absolutely required it. No one is having problems in C/++ because of this. No one is having problems in PHP, either.
And saying this will probably get me the flood of down votes, but this has always struck me as being something that is a language "requirement" only in people who have an itch in a hard-to-reach place in the engineering department of their brain - no offense meant. They need it for their sense of order, not for their software.
Finally makes it much more easy, and much more readable, to do the right thing. Not having finally means duplicated code and harder to follow methods where resources have to be managed, and for most developers, this simply means resources are not managed properly at all.
C++ doesn't need finally because it has deterministic destructors, which are used to emulate finally clauses. In my opinion, destructors can cause less readable/predictable code than a proper finally block, but that might be matter of taste.
Comment from the language maintainer:
The only difference is the second example does rethrow the exception. Though this is still possible (however much more to type) it is wrong design. Since obviously you are using the exceptions as control flow.
This seems quite strange. Finally is a construct to manage control flow, and it's essential to control flow during error conditions. He seems to prefer just swallowing a (potentially critical) exception. Either I'm misreading him, or I think he fails to understand the point of either finally, or exception handling in general.
"Finally makes it much more easy, and much more readable, to do the right thing."
I think this gets to the heart of what feels 'off' about PHP to me: this kind of passive-aggressiveness against "doing the right thing" seems built-in. Kind of like how in order to avoid XSS, PHP offers htmlspecialchars(), or to avoid SQL injection, mysql_real_escape_string() (I'm aware of PDO, but it seems few if any major projects use it).
Question: when are PHP's object destructors called ? I can see some issues with external resources if an object instance hangs around until it is garbage collected. PHP might not have an issue with this if it does GC for every page load, but other languages like the .NET languages can experience serious issues if you don't release external resources using a finally block, and rather rely on the destruction of the object to release them. In such a case, the destruction may take place a long time after the initial acquisition of the external resources.
My point is that object lifetime <> external resource usage duration in all cases.
As soon as there are no more references to it. PHP is reference counted (with cycle detection). As soon as the variable containing an object goes out of scope, the destructor will be called.
The fact that Java/C# destructors aren't called immediately (and may not be called at all) is the primary reason that Java has the finally block (C++ doesn't) and why C# also has the using statement.
Thanks for the response. I knew that PHP was reference counted, but what I was asking (not particularly well) was more along the lines of: is it possible to have objects live longer than the scope of a single script ? IOW, is there a point at which the PHP runtime decides that it is going to collect/reclaim everything, similar to a process termination in the OS ? Or is it literally possible to implicitly allocate objects in a global fashion and have them stick around until the PHP runtime itself is terminated ? Thanks again.
Well, in fact you could serialize/unserialize the objects and store them somewhere, making use of the "magic" functions __sleep() and __wakeup(), if I recall correctly. But yes, as soon as the web server ends the response or the script gets to the end, it's finished
It's extremely common to write code like:
Then you can safely work in a temporary directory: If this doesn't look enough like Java, that's easy to fix: (+) Now you can say: No language feature or bug tracker rant-fest required! And, I'm pretty sure that you can abuse destructors in PHP to get exactly the same result. (In Perl, that "guard" function from the Guard module is implemented something like: class Foo { has 'cleanup' => (is => 'ro', isa => CodeRef ); sub DESTROY { $self->cleanup->() } }; sub guard(&){ return Foo->new( cleanup => $_[0] ) })(+) Also, don't cut-n-paste this code into your apps. It misses special cases. use Try::Tiny, TryCatch, etc. from the CPAN.