I gave a talk the other day to the local Perl group about Perl 6, the language itself. It was intended for regular people who actually use Perl 5 today and may like to use something better, if it isn’t too damn painful to switch. It was a conscious decision to aim the talk at the user, not necessarily someone who’s into language design or compiler implementation. (I know a few people who’d just be impatient with a talk that doesn’t present something new in itself—almost all of what I said can be found on the net—but you gotta choose what you want to say and take into account who you want to say it to.)
Here’s a nice language feature I didn’t mention for lack of time. You know how some languages have exceptions to signal error conditions: the code that detects the problem raises an exception and someone up the call stack who can actually handle the problem catches it. The alternative (in mainstream languages) is to have the function that detected the error return a special value which the caller must interpret as a failure, and explicitly take care of immediately. In c, there are no exceptions, so you always have to write this way.
int
sequence_of_things_to_do() {
if (do_something() == FALSE)
goto error;
if (do_something_else() == FALSE)
goto error;
/* ... */
return TRUE;
error:
handle_error();
return FALSE;
}This is tedious, because you have to write a lot of explicit code to handle what presumably isn’t the common case of program flow: it isn’t what your code is about. Exceptions are of course meant to solve that. They also solve the problem of expressing several different kinds of errors: in the code above,
handle_error doesn’t know what went wrong; but if this were rewritten with exceptions you could have the the utility functions throw different kinds of exceptions and write different catch blocks for each of them.The thing is that sometimes code written with exceptions has its own unwieldiness. One principled objection is that when you look at a piece of code, you should be able to see the flow: with exceptions you do not, because by looking at a function call, you can’t tell if it might throw something. Exceptions, the argument goes, are action at a distance, something which is usually considered a bad thing in programming.1 Less systematically, and despite the example code above, sometimes the specific circumstances are such that non-exceptional code is actually clearer on the page.
So here’s yet another holy war going on about how to design your code: you must, as the author of a module, either raise exceptions on errors or use the function return value. Your user, the client code, is forced to adopt your way. If there’s a project that uses several libraries, there’s the sad possibility that the code will have the ridiculous mixture of exceptional and non-exceptional code in the same block, not out of a literary decision (of what makes sense in context) but out of having to use two disagreeing modules. That sucks, and there’s nothing you can do about it.
In Perl 6, there is something you can do. And it’s remarkably simple to use, too. All you need as a module author is to use a new keyword where you’d previously thrown an exception / returned a failure value:
die "file not found";return ENOENT; # "file not found"fail "file not found";
Now the wonderful part. By default,
fail is synonymous with die, that is, it raises an exception. But at the caller's discretion, it can instead be made to return a false value, and populate a special error variable with the unthrown exception object. The caller can control this behavior lexically, that is, declare no fatal; at one point and have that in effect until the end of the current scope, and have the rest of the program work as before. Poof! The holy war just went away. People will still argue about what’s better, but less often, because a programmer’s decisions won’t be infectious.1 I want to ask people who argue that whether they think virtual methods are also a bad idea.
2 GLib, which introduces many concepts to c, including inheritance and closures—though nobody uses the latter ouside of GLib and GTK itself, they're just too weird in c—also has a way to emulate exceptions. The idea is to pass a "GError" pointer that the called code might populate with an error and immediately return; the caller code is expected to treat the GError according to a certain protocol that gives you most of the interesting semantics of exceptions. Except that the language tax is high; you have to spend a lot of time doing something essentially bureaucratic. This is exactly the kind of thing Perl 6 the language set out to minimize.