 As Jacinta Richardson she is the winner of a white camel award. I know you don't know what it is or do- does anybody here know what a white camel award is? One. Don't tell them. And I'll just hand you straight over to her and she'll begin her talk now. Thank you. Anyone who does care what a white camel award is, ask me later. Anyway, thank you all for coming. I hope you enjoy this talk. There are a whole heap of best practices I would really like to cover. Unfortunately in 35 to 45 minutes that's not going to happen so I'm just going to cover the ones that I like best. Now to get started, in 2005 Dr Damian Conway wrote this book. It has 256 best practices. While several of these practices have over the last five years been considered maybe not best practice or at least opinions have changed on them somewhat, there are still a lot of very very good recommendations in this book. So if you write Pearl Code I strongly recommend getting a copy of Pearl Best Practices by Damian Conway and having a read over it. Just cross about the ones you don't like. Now of course there are many obvious best practices and the book covers quite a few of them. And I'm not going to waste time on all the obvious ones because you've almost certainly heard of them before. So stupid over quick mention, obviously you are using strict and warnings. That's not going to surprise anybody. If you aren't using these hopefully you know why you're not using this. I hope that you're using scalar file handles and three argument open. They've been in the language for more than 10 years now. It's probably about time that you found them worthwhile. Of course most importantly I trust that your company has coding standards and that they are more verbose and more interesting than just use strict and use warnings. So let's look at things that aren't as obvious. Some of these things are a lot less than five years old. This one isn't. Upgrade your version of Pearl. I still have customers terrifyingly enough who are using Pearl 5.00503. Some of them are using 5.6.0 which is more than 10 years old. Upgrade already. Timeline to give you an idea of how ancient your version of Pearl is. Notice that 5.6.1 is almost 10 years old. It'll be 10 in April. Are you using an operating system that is more than 10 years old? Hopefully not. Debian Lenny ships with 5.10.0. It ships with 5.8.8. If Debian can do it you can do it too. 5.10.0 is already three years old. It's not like Debian is being leading edge still. I recommend picking one of these versions if you can. So if you must stay in the 5.8 branch for some reason, upgrade to 5.8.9. If you're allowed to be brave, skip all the way down to 5.12. Pick your new version. If you want to take advantage of the new features that have come in, just write this in your code. Use v and the version of Pearl that you've done that you've picked. This will give you all the new features and you can go forward and have fun. It also tells Pearl, of course, that this is your minimum version of Pearl that you're going to, that you're targeting. So obviously your more ancient versions of Pearl will not be able to run this. That's right. If you use this, you get all the features that come in. You don't have to use the features module itself. If you're going to ask a question, could you use a microphone for the sake of our AV operator up there? New features. Let's have a look. After 20 years, actually 21 years, Pearl finally has a print line. It's called C. It's print with a new line at the end. How awesome is that? Indeed. Plus, of course, it mentions dollar underscore, which is terrible. We can get rid of all of these red characters here. In particular, we can get rid of dollar underscore. Say hello world. Since we're not giving it an argument, it's the default argument with a new line for everything in my list. Drop the each in the foreach. I like the foreach better. Or returns true if the value is defined or considers any defined value to be true. So we're not saying is it true or false. We're saying is it defined or not defined. Let's set up an example. Here we want to handle the sale of an item price. Now, the price may have discounts applied to it. We're calling this internally. We're not allowing the user to give us a price so we can trust the price that we have here. If the price is false, which includes zero, then we grab the cost out of the product. If the price is false, way an item for free. I'm using this as a way to add things to an invoice except that I want to give a bonus item away for free because they've already ordered four of them. This code that I have will reset that to the full price. We can fix this problem, of course. That's how it might be a bug. We can fix this problem like this. This is how most of you have tried to solve this problem before. Unless my value is defined, set it to the cost. Okay, but it complicates the code. The all equals much, much easier. Or we can use defined all. Price defined all product cost. So now we're saying if the value is defined, we keep that value. If it's zero, that's okay. Otherwise, set it to a value. If we don't pass in a price, the price gets set to the cost. If we do pass in a price and it's zero, we keep that zero. So defined all is pretty awesome. We also have state variables. These are really a lot like C's static variables. So it's kind of a surprise that they took 21 years to get into the language as well. Very simple example. We want to keep track of how many images have been viewed. And we want to die if we grow over some number. We can't do this inside the subroutine. Because if we said my image is the loud equals zero inside the subroutine, it would just set that to zero every time, to 100 every time. Outside the subroutine like this, then other subroutines can see and potentially change this value. So traditionally we solve this with a closure. And now suddenly your subroutine is not against the left-hand margin. And that makes people sad. Or perhaps we create an entire object layer to handle this. And that's way too many lines of code, so I decided not to show you that. Or a state variable. A state variable, when Paul sees this, it runs that line once, sets it to 100. Thereafter it does not run that line again. That value remains private to the subroutine or to any enclosing block that is declared. But it remembers the state that it last had. It's pretty awesome. So given a when, this is like a switch statement on steroids. So here's an example. Given some value a dollar has, if it matches any of these three regular expressions, then increment the value in my block there. If it's a value in this array, then we're going to increment our others. If it is a key in our hash percentage cool, then we're going to increment our cool or do some other code if we wanted to. If we have gone through all of those, our final else, we just increment borrow. If we wish to, we can actually say continue inside our blocks and it will continue on doing the rest of the tests. So we have these as choices. So given when is switch on steroids. And what's more, it works with foreach as well. So we don't have to have the given, we can just say for each all the items in this list. When this, when this, when this, when this, and a default. It's because of smart matching. Smart matching looks a lot like this and we invoke it with tilde, tilde. Is through undefined? Is through a member of this array? Is foo a key in this hash? That should be tilde, tilde. Oops. Does the subroutine in this code ref over here return a true value when given foo is an argument? Does foo match this regular expression? It might be an array reference. Is it an element in this array or a hash reference is it a key in this hash or even just the string? Are they string compare equal? So smart match does the right thing. Highly magic way. Very cool. And there's some cool things in newer versions of Perl as well. Let's have a look at how Perl handles failure. By default, Perl's built-ins return silently on failure. So you have to say open this file and then all did that succeed. Change to this directory, all did that succeed. And you'll all be very familiar with this. But really it's heartbreakingly terrible. It means that you actually have to rely on your programmers to always do the right thing. Programmers don't always do the right thing. And it's the one you forgot to check that is causing your program the buck. Like this. Open my file for reading or die with some error. Read from my file. Close my file or die with some error. Change my directory or die with some error. Do these other things or die with some error. And that's just frustrating. And some of Perl's built-in functions return false values on success. So you can't always say and die. For example, system says zero for success. So you have to say system and die. There's a lot of error code here. Pluttering up our program. Now of course we might have stopped reading from the file before we closed it. There might have been some other error there. Not sure how you catch it. These things can get quite difficult. From 5.10.1 auto die comes standard with Perl. So if you're upgraded to 5.10.1 or better, you already have auto die. Otherwise you can download it from the cpan for versions of 5.8 and above. Here we say use auto die. That makes Perl's built-ins auto dying. And then we just succeed or our program automatically throws an exception for us. Excellent. And our code is way, way neater and more correct. These exceptions are failure. Sometimes we might want to do something but not have it throw that exception. Or more importantly we might want to catch that exception. How can we catch these? The traditional incredibly ugly way of doing this is a block eval. Who's never seen block eval before? Excellent. So from this semicolon at the end of eval that you can't see because it just doesn't look obvious, that's required. Code doesn't work otherwise. Eval says run this code and when it throws an exception, capture that and stuff it into dollar at. Because that's a meaningful variable. This is how Perl spells try and catch. But we can fix that. Because we can use try tiny which gives us try and catch semantics. So try this block of code. If it succeeds, we skip the catch block. If it throws an exception, we catch that exception and it puts the value in dollar exclamation mark. Much more reasonable. Other exceptions or other, so yes. Finally as well as a block. Yes, we have finally blocks as well. Other exceptions. Modules when we write them should not throw exceptions with die. Let's see why not. Here's a really trivial module. Package greetings. We create a hash with some basic language code and greetings in them. Here I've been really lazy and I've just defined English Australian. We take a subroutine. The subroutine takes a language out of our underscore and it looks up. Do we have that greeting in our hash? If it does, it returns the greeting. Otherwise, it dies with an exception. When we run this code, we might get this. I don't know what JP is at greetings.pm9. 100 times where I call that greet subroutine. Which one of them passed in JP? Where was my code at fault? We use carp and carp's been around for a very long time. If instead we use carp, we can croak. Croak. I don't know that language. And now we have I don't know JP at greet line 3D. What we get to say is I'm throwing an error, but is that piece of code over there's fault? Not my fault. That code over there. And you can do stack back traces and such if you'd like to. You have to upgrade and I've shown you awesome new features, but you might be thinking I'm not allowed to. I can't upgrade my code, upgrade my version of pill because it might break my existing code. And I can't test whether or not my existing code will break because I can't upgrade my version of pill. It's a quandary. People get stuck in this one. But there's a very, very good and easy solution. AppPulbrew allows you to fetch, build, compile and install whichever version of pill you'd like to with permissions in your home directory. It takes a little while, but you get pill in your home directory for as many versions of it as you have patience for. You can even install onto removable devices. This is how we start and we fetch pillbrew to get going, and you only ever need to do this once. This is all in the man page as well. Once we have pillbrew, we just install the version we want. Pillbrew install pill-5.12.2, install that version on pill onto your machine. If it then sets our path so that this version of pill is found. It doesn't kill our path, it just adds to it. So now we run pill-3, we now have pill version 5.12.2. We can see the list of pill versions available to us. We can switch between the versions we have and we can turn pillbrew off. We turn it off, it just removes the part added to your path so that you go back to using the system pill. Pillbrew makes upgrading easy. It's awesome. Your code needs modules too. Fine, you say. Fine, I can test the latest version of pill, but what about the latest modules? Modules are hard. Installing modules into your home directory isn't as easy as it ought to be. And I don't want to cut and paste them, I'll try to compile them manually. There's a good solution for that one too. Local lib makes handling local modules easy. We bootstrap it like this, assuming you can't convince your sys admin to install it for you. In our code, say use local lib. If we say use local lib, by default it assumes that it's installed into your home directory, pill-5 directory. If you want, you can pass in a team, sorry, a directory to a bunch of other things instead of just using lib. Alternately, and it's much, much cooler, if you allow it to, say local lib wants to set all of these environment variables for you. And once you have allowed it to set these, just put them in your bashrc file, your TC shell. Once you've done this, in order to use your local directory of modules, you want this. That's right. Once those are set, it all just works. Do your own version of Perl. We're using our own version of modules. How do we install them? The modules, that is. We recommend cpan-m. It fetches, builds and installs your modules. It knows about local lib, as I'll show you in a second. And it does the sensible thing. It's quiet. It doesn't say, hey, I just found this extra dependency. Do you want me to add it to the chain? Of course they do. No, you're going to say cpan-m install this module. And it goes and it does the entire thing for you as quietly as possible. No pages and pages and pages of cpan-output. Again, bootstrapping it is easy if you can't get your system into install it for you. And then you install it like this. And as I said, it knows about local lib. So here it's just using local lib setup for default. If you have set up your environment variables, oh, yeah, there we go. We just say cpan-m test most or whichever module we want to install. And life becomes much easier. Start writing modules. That's not too hard either. Module starter is a great way to start off. You run on the command line. You pass in a bunch of variables. Preferably you include your build system. And in return it makes for you module stops for all the modules you specified. And it fills those out with example documentation. And it creates tests for all of them to make sure that they're loaded. And it gives you a make file and a changes file and a to-do file and all the files that you'd usually want to start off with. It gives you most of a distribution that passes all of its tests, although it doesn't do anything, straight away. Much, much easier to start if you switch. What was that? They fail because one of the tests is a check that's done. Because it's done. Schwer is going to say that it doesn't pass all of its tests because one of the tests checks that you have changed the stub documentation. Fortunately this is actually not an issue because it requires that you have turned on all the tests for that to fail. Documentation for a moment. Because indeed you don't want to leave your stub documentation in. But comments in your code, whilst really, really useful to other people, might be considered a little bit boring. I know a lot of people who don't update their comments when they update their code and that's a bit of a problem. But comments can be smart. Comments can tell you about stuff that is happening in your code when your code is running. That's pretty awesome. We do this with a smart comments module. Smart comments module, we create a bunch of special comments and these do things when our code is run. So here we're saying expected and we're doing a small expression and it's going to print out that result there. It's going to tell us what cookie is. And it's going to look as we run through our loop and tell us how we are going through that loop iteration wise. And if I ran this code, about 70% of the way through the loop, I would get this. Expected 30 got 30 eating cookies. And I'd get more dots as time went on. 77% done. So your comments can be smart. And then when you just comment out smart comments at the, I want your code is ready, they're useful comments that people can read later. Now let's move on to tests. Tests and Perl is actually pretty easy. Here are some different ones. OK says is my first argument true. Is compares the first and the second argument and says are they the same. EQ or diff says are the two strings I have the same? If they aren't, it gives you a diff of the two strings. So you know where the difference is. Die is OK. Does this method I'm about to call throw an exception. There are lots and lots of different types of tests available. I strongly recommend writing more tests. Test most is an aggregation of the most popular test modules. And I've listed these all out here. Exceptions, differences, deep warns and more. And there's tests, no warnings as well, which allows you to ensure that your code does not emit warnings during the run of the test suite. Because if your code is emitting warnings, you are later going to fill up your log files. And that would be bad. To help ensure that your tests are testing what you want them to test, use Devel Cover. It's very easy to run Devel Cover. You write cover minus test in your test directory. And it has a bit of a reputation for being right once. And so there are a lot of messy programs out there that I hope I don't ever get asked to fix. You probably encountered a few yourself. Some of this can be fixed by just tidying up the code. And if you had to do that manually, that would be terrible. So we can use Piltity to make your code beautiful. For example, we can go from this mess here to this mess here. This is actually still kind of ugly. But it's pretty. And you've written it and you've got your modules working beautifully. And you have tests and such. Hopefully at some point in your organizational chain of doing these things, you will actually be reviewing your code. Or rather, someone else will be reviewing your code. And they'll come back and they'll say, hey, you know, you chose this algorithm, but this one over here would be faster. Or they'll just give you feedback. You know, you've done this, but that's a really terrible way of approaching it. Or you've done it. That's fantastic. I'm going to steal that for next time. Hopefully you've got someone else who looks at your code and gives you feedback and helps you learn, and they learn from you. Some of that at least can be automated. You don't really want to turn up to your code review and have the first thing the person says to you is, hey, you haven't yet turned strict on. Go turn strict on, fix all those issues, and then come back. And you come back and you forgot warnings. Go and fix all the warnings and stuff. There are things like that are obvious code review things. It can make it, it can do that work for you. So, Pearl Critic can review your code view in the ways that are easy to automate. It won't correct your algorithms. It won't do the things that a fellow programmer can, but it can complain about important things. Here is an example. This is actually run over that ugly example I showed you just a moment ago. Pearl Critic has read Conway's book, and it will tell you what you are doing that is wrong. And it will tell you why. It will say, see pages 68 and 71 of Pearl Best Practices. Or 236. And it colors these so you know which ones are most severe. It's most unhappy that there was code before I said use strict. It was only, it was less happy about the purple stuff and very unhappy about the black stuff. So, somewhat okay with the black stuff. So, it color codes this. The things that are right red sticking out at you. You have done this. You shouldn't do that. It helps you out there. It's a pearl practice I can give you. And you'll all know this one, which is fantastic, is don't reinvent the wheel. C-Pan is Pearl's biggest strength. If there's a module on C-Pan that does what you need to do, don't do it. Just use the module. But I am going to mention a few specific wheels that I really love and want to encourage you to consider. Now, first of these obvious ones that everyone seems to forget. Scaler, U-Till, List, U-Till, Hash, U-Till. All those three that I mentioned come standard with Pearl. List more U-Tills doesn't, but it's not so bad. They all have useful subroutines in them to just help you do the little things. For example, if you want to randomize a list, randomize a list. Just use List, U-Till, Shuffle, come standard with Pearl. There is no penalty for using this. And it's better than trying to use an unbalanced... So, what is the phrase? Trying to sort with a RAND inside your sort block. An object or a national mapping. Rather than writing SQL directly into your code. By the time you're doing anything with a database, your code is probably sufficiently complex that mixing up two languages is going to be more problematic than just keeping one. There's also a good chance that any ORM you pick will write better SQL than you do by default. Just wait for a moment please. Okay, so the assertion here is that any random SQL you write yourself is probably less good than what your ORM is going to give you. No, the problem is that whenever you actually manage to get a DBA into the picture, it's usually easier for the DBA to fix SQL than any code written by your ORM. Humans are really, really good at writing good SQL code. Okay, I agree that if you need to get a DBA in at all, then you probably already have a problem. However, if you're just writing something to update tables, pull the data out, and all of those kind of things, which is the vast majority of this kind of work, and you don't need to write specialized queries, the average program is going to find it easier to do this. So if you ever need to refactor your database, the ORM gets in the way horribly. Yeah, it shouldn't. It does. No, your ORM gets. You can do either. We will talk about that later. So ORMs turn database rows into objects and relationships with other tables into methods. These are the two that are most loved at the moment. Also, a bunch of frameworks you should be aware of. I'm just going to mention two of them. Catalyst is Perl's salute to Ruby on Rails. It's fast, flexible, and elegant. And it's probably about equally as difficult to learn. And Moose is a post-modern operating system. There, what do I mean? Object system. OO under Moose is gorgeous. If you hated OO under Perl before, Moose makes it all better. Well, a lot, lot better. All the pain from multiple inheritance is reduced because you start using roles or in other languages, you might know them as traits. I'd love to cover this more, but it's a whole talk on its own. I will happily tell you more about it later if you grab me, though. So add antlers to your code. Well, let's face it, uglier than every other language out there. Well, subroutines don't have any useful way to declare your arguments at the point where you create your subroutine. Even C lets us do that. This is terrible. Act them from add underscore. And if we forget the add underscore bit over there and put a semicolon, we've just created two undefined values. I've done that way too many times. There are a whole bunch of problems with just trying to unpack our variables from add underscore, including the fact that we don't, there's no easy way to say in advance that this is how many arguments our subroutine expects. We might unpack a few from add underscore here and then some more from add underscore later in our subroutine. Hopefully you never do that, but I have dealt with code that does. So this is heartbreaking. Again, I really, really hate the fact that the start of our subroutines has these problems. So after 21 years, we've made it better. Method signatures allows us to say, this is what our subroutine looks like. This is how we call our subroutine. Plunk instead of sub, the name of our subroutine, and then we pass in our arguments. Isn't that so much more awesome? We don't have to worry about add underscore anymore or trying to explain to other people what that means. It also gives us methods. So if we are dealing with objects and we want to create a method, method get and the arguments we pass in, and we can call our subroutines there. Now it's worth noting here, I'll let you ask a question in a moment. Self is springing into existence, it would seem. That's because you're calling a method. So clearly you're going to be operating on an object and that gets populated as dollar self to start with. Yes, Michael. When you call a method, what happens if the signatures don't match? What happens if there's only two arguments specified and you try to call it with three? Will it whinge and complain and bitch or not? Yes, it will. Thank you. Practice is the code for portability. If you ever have to deal with a file system, any kind of interaction with that file system, try not to code your, to tie your code to any particular system. If you had code forward slash is in or backslashes in to your code, other operating systems might not understand your directory interaction. For example, how do you move up a parent directory? Is it always under every system ever dot dot? Probably not. How do you address a file? All these things. Path class makes file system interaction easier by abstracting away the interaction. Let's use path class. My directory is foo something bar something bad. I'll let it work out for my operating system what that something in between them is. Obviously under unix it's forward slashers. If I want to go up the parent directory, I just say go to parent. If I want to jump up two parent directories at once, I can do that too. Close the files so I can create myself a file. This directory with this file name and under windows it gives me my backslashes. And the very, very nice thing about this is I don't have to go, oh, that's right. I'm doing this under windows. I can't use double quotes. And go and escape all those characters. Regular expressions. Regular expressions are a language within a language. So what are you dealing with two languages before we even add SQL? It isn't regular. So regular expressions aren't really either. Somewhat misnamed, I would say. I've got a few hints here of things you can do to make your regular expressions more awesome as well. So use the slash a and slash z meta characters. These will make your life easier. At least they ought to. Have a regular expression, hat, find me at the start. Without the m there, this hat matches the start of the string. When our colleague helpfully adds the m later, the m modifier says process our data in a line by line mode in a sense. Then now this will match the start of any line within that string. If we wish to match the absolute start of the string, we should use slash capital A. And you should do this even when you are not adding the m modifier. Just in case later, your colleague does add it. With the m modifier, dollar matches the end of line. So instead of the end of string, it matches the end of line. If we want to match the end of the string in the same way that dollar would have, we use slash capital Z. So use this whenever you want to actually match the start of string or the end of string. This will actually match the end of the string just before the new line character if there is a new line character, just like dollar does. If you want to match the absolute end of string and you have to deal with the representation of a new line if it's there, slash capital slash lowercase z will do that for you. But I'm surprised at how many people get this wrong. Be aware, be proud of and enthusiastic about the fact that Perl allows you to use other delimiters. We do not have to write this. Have we got enough there? I never know. Because we can write this instead. I like curlies. You might prefer square brackets. It doesn't actually matter if you pick one that already appears in your regular expressions as meta characters because Perl knows how to work out where the things balance. So change the delimiters to be something that isn't going to mess up your data. Your regular expressions out of QR fragments if that makes sense. QR for quoted regular expression. It's like we have qq for quote a double double quoted string and single q and qx. QR for quoted regular expression. This is a fairly trivial example. Here I'm matching against my line some word characters followed by full colon followed by some word characters, a space and equals a space and some more word characters. And we could fragment this if we wanted to. We could say everything on the left hand side of the equal side and everything on the right hand side of the equal side. This is a really simple example so maybe you wouldn't bother. But unfortunately if I showed you a very big example it would take longer to explain it. So here we've split it up. Our left hand side of the equal side and our right hand side. So word characters followed by full colon followed by word characters and just word characters. And that's what our regular expression now looks like because we just insert those in and interpolation means that that all works. But we do have a small little problem. It's possible that we will unpack what we've captured in this case dollar one, two and three at a decent distance from where we defined dollar LHS and dollar RHS. So we may not be able to look at these four lines of code and be sure that we got that right. In fact we might wonder, hang on, was that right instead? It's hard to tell. What if we mess up the order of those variables we're capturing into? Things will go strange. Fortunately named captures make this so much easier and much, much, much more awesome. We have those from 5.10.0 and above as well. So for the last three years characters populate the special hash percentage plus. So we can pull our values out like this. Type is dollar plus type. Name is dollar plus name. Value is dollar plus value. And that's really awesome because unlike dollar one, two and three we can make sure that we're actually getting the type variable from type, the name variable from name. Capture into percentage plus. We name our captures like this. Question mark and then the name. Question mark and then the name. If we have multiple captures with the same name then they go into an array reference stored in the special hash called percentage minus. Now just as we shouldn't reinvent the wheel if there's a CPAP module that already does what you're going to do, you should avoid writing regular expressions that have already been written for you. Rather than thinking that you are perfectly capable of writing a regular expression to match an email address, maybe you should use what someone else has done. Expressions for all of these things. Didn't test the IPv6 one? That one might actually be wrong. I doubt it would be but I really don't know. That's right. Excellent because I know there's all sorts of magic stuff with IPv6 that I don't understand. It has a profanity. It has a regular expression for common profanity and it's what 13 so that you can't offend yourself. Magic is common to save yourself some effort with the regular expressions as well because they're all the common regular expressions. Yes. Jeff, it's actually a number of them. Not all of them but if you, so the question was which country post codes am I saying this matches and that really just depends on which other modules you have installed. But yes you can get Australian post codes if that's what you're particularly interested in. So I think that's a little bit more awesome than just regular expression. I mean there's a lot of things we shouldn't be doing with regular expressions and then there are some things that we want to be doing with regular expressions that we may not, maybe we shouldn't be doing anyway. Perhaps you want to write a grammar. Well, Pro 5.10 made grammars much, much easier just by including them in the language. Pro grammars for everyone. And here's an example. So what this regular expression does, this is why the complicated regular expression is it matches an expression by which I mean a mathematical expression. A equals 5 or A equals B minus C equals D. So what it says is it says an expression is a term optionally followed by an opt term being an optional term. A term is an identifier or a number. An opt term is an operator followed by a term optionally followed by an operator, sorry by another optional term. An operator is any of those standard mathematical ones. An identifier is a sequence of letters followed by numbers. And a number is of course just a digit. So this defines the grammar we would need to match a mathematical expression. And we could say if A plus 7 equals B minus 2, if that matches our expression, we say yes. And indeed that runs and says yes. If we tried A equals 1 plus nothing, then that will not say yes. Because that is not a valid expression. We have a term there that is not, sorry, an operator there that is not followed by a term. Is everyone cool with that? Okay, so there's a small problem with this. What were our terms? What were our operators? Yes, it's great to know it matched. What if I want to pull it apart now? Give me my parse tree. Can I have my parse tree? No. No, no parse tree for you. The syntax doesn't give us a way of accessing this information. We can only say yes we matched or no we can't. So Damien Conway, who wrote that excellent book I mentioned at the start, fixes this for us. He wrote a module called regex grammars. And this allows us to write a grammar that takes advantage of this system underneath, but keeps our parse tree for us. The syntax is a little bit different. Essentially the same thing, but we have to define these as rules, which actually makes them, I think, a little bit NATO and easier to read. Now if we say a equals 5 plus 1 expressions, if that succeeds, this populates the hash called forward slash, which as you could see is a very meaningful variable now. And for the simple expression a equals 5 plus 1, we get this beautiful tree here. Now I know that this is kind of complex and I'm not giving you enough space to read, I haven't given you enough size of characters here to read that all, but it was mostly just to show you that it does actually break everything down. So we can see at the top level the empty key is our expression. You can see what the expression was and how it was decomposed. Then our op terms, where we're up to and what our term was, our operators and so on. If you do need to parse a grammar, this is a great way to do it. Much, much better than trying to do it on your own. If you missed Michael Schwurn's talk on Monday, please watch it online. Perl5i, Perl5improved, combines many of these great ideas into one package which gives you an idea of what Perl5i might be, or what Perl5 might be if we wrote it today, which is in some ways an idea of what Perl6 will be. And he gave me some excellent examples to show you. So here's some fairly standard Perl5 code. We want to write an ISO 8601 timestamp into a file. Should be an easy thing to do. And this is not bad code. Any version of Perl from 5.8 and above will happily run this code. So we use a whole stack of modules, create our subroutine, which opens the file, prints the line to it, and closes the file. And to create the ISO 8601, we use the stirriff time thing here. The problem is that that's a lot of code for something that should be a really simple idea. Perl5i, it looks like this, which I'm sure you'll agree is a lot less code and a lot nicer. C12 file handle, local time goes to ISO 8601. Easy. These are the things that are covered lightening fast. All very, very cool. These slides will be available for those who want to play with them. Are there any questions? More of a comment regarding exception handling. If you're not using a web frame, which doesn't already do it, a top level signal handler to catch the worn and die signals and generate a fault report and give you that information. Environment variables, backstab, backtrace, is a really, really invaluable tool. Autoday is a better tool because the best thing about Autoday is that it gives you really nice error messages. For example, if you fail to open a file, it'll say something like could not open file name for reading reason why at this line, at this reason. Whereas by the time you throw in the die and you've caught it in the signal hand and you start processing that, you may have lost, you may already have lost what's on the $1 at because that's a little tad too volatile. And there are a wealth of problems. It is certainly not a bad option to have a top level signal handler to catch dies, but it's really a measure of last resort. Shwern has a comment on that. Yeah, the problem with a top level die signal handler is that it's global. Somebody else will decide that's a great idea as well and put theirs in this place. And then your entire exception handling system goes away. Yes. Thank you very much indeed, Jacinta. Time is up. You've had your time, but Jacinta's going to be packing up for a while and you can ask your questions and those of you who have. We've got a little gift here to show our appreciation for your talk. You did good, Teach. It was really nice. Put your hands together for Jacinta, please.