|Just another Perl shrine|
In reading through M. Conway's Best Practices, I must say that there are a few areas where I'm disappointed to discover that he's not enlightened enough for my one true way ™. For the most part, though, I'm quite delighted to find eloquently stated reasons backing up many things I do. I was particularly happy to find him recommending programmers not use tied variables or lvalue subs. They've always struck me as hacks. And what do those hacks buy us? Well, nothing, really. OK, some tied hashes are useful, but I think said usefulness is overblown.
I know how to tie variables, but I don't like to. In fact, I can't recall a single time I've tied a variable in production code. If one really needs to alter the semantics of built-in datatypes, switch to a damned object, will ya? Tied variables are slow, they're mysterious if you don't realize they're tied (this has caused me a lot of pain) and it's easy to implement them incorrectly. One of their biggest problems is that you can't just look at a single line of code with them and know that something is amiss.
And this brings me to lvalue subs (not just lvalues, as He Who Must Not Be Named pointed out below). These little beasties, in case you're not familiar with them, are what's known as a "big bucket of suck". They let you do this:
This brings up an interesting question. Why would I, the conscientous Perl programmer, want to throw away my hard-won encapsulation by switching to lvalues? Yeah, I was lazy and saved a line of code in my name method, but that's a bad lazy. I can no longer validate my data. Of course, some lvalue fans argue that I can use tie to get my validation back. Great! Now I've lost much of the conciseness I've hoped to gain and I've probably moved the data validation code away from the method in which the maintenance programmer expects to see it but at least I've switched to a slow, confusing and fragile interface! And hey, if you disagree with that, go argue with the Damianator who already took a Gatling gun to tie. (Wouldn't that have made an interesting movie? "I'll be back, mate." However, I'm not sure switching from an Austrian to an Australian accent would inspire the right amount of dread).
And while we're at it, I can't say I'm a huge fan of overloading accessors to also be mutators. I've done it, but I don't like it. It turns out that the Damianator recommends against this, too. It's easy to write buggy code:
Answer quickly! Does the following set the name or not?$object->name(@name);
The short answer: maybe. You see, it's impossible to tell by visual inspection if that array has any elements. You can trace through the code and guess, but now you've lost data validation (throwing away information is rarely a good idea) and have a silent failure. Compare that with this:
Of course, once you start overloading the method name, what happens if you have a method which returns a value you can't set? Such as the database row id?
Does that silently fail? Did that accidentally change the ID you weren't supposed to change? Did you remember to throw an exception with a reasonable error message? Did the programmer using your code curse you out for not making it obvious what you can and cannot do with the methods? With proper getters and setters, you would not have these issues:
And the error:Can't locate object method "set_id" via package ...
Now, we get a verbose failure and a reasonable error message without writing any code to do this. That's good Laziness.
tie, lvalue subs, and overloaded getter/setters: do leave home without 'em.
What features of Perl do you deliberately avoid and why?
New address of my CGI Course.
Side note: lvalues got me to thinking about method call syntax. Geoff asks why some coding standards might require parentheses for method calls. One respondent speculated this might be a sop for those coming from other languages. Some languages (*cough* Java *cough*) alternatively require/forbid parentheses depending upon whether you're calling a method or accessing a property. Frankly, I don't like it when languages such as Java which force me to put the parentheses on a method call. In an OO point of view, why should I care that the value 42 was a property or computed on the fly? What if I hard-coded it at first and didn't encapsulate it in a method and later decided to calculate it? Yes, creating a property without encapsulation is a sign of bad design, but can anyone tell me why on earth it would be a good idea to allow that in a language? I'm stumped.