08 September 2007

Things I Miss When Programming in PHP

Ok. This isn't meant to be an entry just about trash-talking PHP. It's more of an entry discussing what are the things that are missing from PHP with regards to database-driven web site development. I do like PHP and of all the languages I've used "in the wild" so to speak PHP is the one I've got the most experience with. Still, I've got a few bones to pick with it so there may be a little trash-talking involved here.

Lack of Functional-ness
My programming background is pretty heavy with cryptography and artificial intelligence, so I feel like I really shine when I'm programming in functional languages like Ocaml, Haskell, Lisp and to a limited extent Scheme. I've even been known to bust out with some Prolog where appropriate. I think it's completely unreasonable to expect a language like PHP to have things like functional currying or functional pattern-matching, but I don't think it's unreasonable to expect some amount of functional programming magic to be possible.

For one, recursion is a no-no in PHP because there is no tail recursion. This may change in the future, but it's a pain to do recursion in PHP anyway and you're better off with a while loop and a stack (which is what tail-recursion turns into on the machine code side anyway). That's a bit of a pain because there are certain processes which are intuitively recursive processes, and these should be workable that way without penalty. Though I have made recursive functions in PHP and used them in quasi-production environments, that's outside the best practices for the language and I would never do it if I knew the system running my code was short on memory. Also, even without ordinary memory limitations, PHP's runtime can be configured to limit stack and heap space artificially, so recursion can still be a bad thing on systems that have plenty of memory.

Another beautiful functional programming trick is mappings. I love mappings. I mentioned list comprehensions just earlier (without calling them that), but if I had to choose one or the other I'd choose mappings. In python, ocaml, haskell, lisp, scheme, ruby, and a few more languages, there is a syntax for "Take each item in this list, apply this function to it, and return me a list of the results". It sounds less useful than it really is, but this is an amazing tool that you can use for all kinds of magic. Right up there with mappings are functional folds, where you can say "Take the items of this list and put this operator or function between all the elements, tacking on this constant to the end; return the result of that whatever it is." For example if you folded the "+" operator with 0 as the constant, you'd get the sum of a list. This is also handy for taking a list of words and appending them all together into one big string. In Haskell and Ocaml you can fold on the left or on the right but watch out, 'cause the right-hand fold is not tail-recursive.

Cons Über Alles
Another problem is the Array construct in PHP, which doesn't actually behave like an array at all but instead works like a hash table. The problem here is that sometimes I have an array that I wish to access like a hash (random-access), but oftentimes I want something that behaves like a List. Lists in functional languages get turned into single or double linked lists in memory, which is just peachy. In Haskell (and, I believe with some magic, Ocaml), you can even have the tail links to these lists pointing to thunks of code that generate the remainder of the list on-demand. That's not necessary for PHP, but it would be really nice to be able to have some kind of data structure native to the language that behaves like a list (or, for all you functional space cadets, a cons). This falls into the same category as recursion, because lists (at least single linked lists) are inherently recursive structures. I miss them.

We <3>
There's no built-in support for regular expressions. Now, I know what you're thinking: there isn't any built-in support for them in Ocaml or Haskell or Lisp either. They're library functions in those languages. But you know what? In Ocaml I don't have to type a mouthful like "preg_replace()" when all I want to do is the same thing the s/// operator in perl does. I know that perl's syntax is confusing as hell to people who are unfamiliar with it (and also to some who are quite familiar with it) but why shouldn't common things like that be a symbol rather than a long-ass function name? While we're on the subject, why are all the functions in PHP so long? Seems there's gotta be an easier way to handle them all.

Get Out of the C++ Mentality
One of the really powerful features of Ruby that scared the bejesus out of me at first but I grew to love is the fact that you can, anywhere you want, add or remove functions or members from classes. This is really scary but really powerful. A lot of the cooler features of Ruby on Rails would be completely impossible without this. For instance you would not be able to have something like acts_as_authenticated or acts_as_taggable, which are functions that shove code from plugins into your existing classes. In PHP you have to have separate classes or subclasses to do this kind of work and it's kind of a pain. Why not just have code blocks hanging around that you can swap in and out of where you need them when you need them? This is, of course, because PHP is a C++ derivative and Ruby is a Smalltalk derivative. Both have their advantages, but this is one of those pure object-oriented things that should've crossed over.

Lemme see... what else. If I had any choice about it, I'd program web sites in Python or Ruby, but Python doesn't integrate very well that way, being that it doesn't have the inline HTML magic that PHP and Ruby both have. I'm still a little uneasy about the syntax of Ruby, too, even though it looks like it should be something very familiar to me (it looks like Ocaml sometimes). Meh. We'll see.

Ok. Back to work for me. Later, space cadets.

No comments: