As I mentioned to Scott when we talked the other night, I've been using PHP to prototype some of my non-GUI projects.
I've found that while prototyping does take a lot of extra time, it really helps to crystallize which design elements are necessary and which aren't and provides insight into what tradeoffs to make between simplicity and abstraction. It turns out that PHP is pretty good at this — it makes the tedious things less tedious but still exposes the hard design decisions.
I started using PHP for web work because I thought it was time to learn a new language and was tired of relearning the finer points of Perl every time I started a new project. I was initially drawn to PHP4 for two reasons. First, on the surface it seemed dirt simple. It has objects, arrays, the standard control structures, and that's about it. There is a certain minimalism in PHP that is quite appealing. Unfortunately, as I soon found out, it is still a pretty immature language and has a couple of really annoying gotcha's. Second, I was quite enamored with how PHP turns the usual scripting paradigm on its head. In PHP, the scripting logic is embedded in the text (in my case, HTML, mostly) rather than the other way around. It reminded me of Knuth's Literate Programming. This, too, was something of a disappointment; it turns out that in practice, for any non-trivial web application, at least, you end up wrapping almost all your HTML inside PHP methods, which defeats the point.
Still, I really like PHP, and it has become my language of choice for web work. I am really looking forward to the time when PHP5 is widely deployed — I wish I could say the same for Perl 6.
PHP is full-featured enough that there can be an (almost) 1-1 correspondence between the objects and methods in the prototype and those in the actual implementation but is just crappy enough that you're not tempted to use prototype in production.
Code can be written very quickly in PHP because it is dynamically typed, dynamically bound, and dynamically interpreted. This makes debugging harder, because the compiler can't catch as much, and most bugs don't show up until runtime. In a prototype, though, you're more interested in design bugs. Anyway, I'd like to see a statically-typed language that can catch those. PHP's ease of string, array, and dictionary manipulation is wonderful in this regard, too. You can optimize for performance, algorithmic, or otherwise, when the prototype is done.
PHP is particularly well-suited to prototyping Objective-C data models. Perhaps, when it comes down to it, this is because they are both relatively immature languages. Objective-C was incredibly advanced, for its time, but it doesn't seem to have grown up much since then. The real power in Objective-C comes from the Cocoa libraries and not from the language itself. PHP4 is pretty nifty but is deficient in a bunch of odd and unexpected areas (PHP5 fixes some of these, though). Neither language seems to be quite finished, really. Still, they are both quite useful, especially if you know when to embrace the rough edges and when to run from them.
PHP is introspective enough that you can use it to implement Cocoa's delegation pattern, wherein instead of creating a subclass to add functionality, you provide a separate object, called a delegate, that is is queried and notified whenever the class wants to do something interesting. This isn't all that unusual (Java has a similar listener pattern, for example). What makes Cocoa's approach so rewarding is that there is no typed relationship between the object in question and its delegate. If a delegate is interested in receiving a particular message from the object, it implements a method with the message name. If the delegate doesn't care, it doesn't. Then when an object does something interesting, it uses introspection to see if the delegate implements a method for the message in question and, if so, calls it. An example in PHP, from my own code, is:
function notifyWeDidFindFileInDirectoryWithPath($file_name, $parent_path) {
if (method_exists($this->delegate, "directoryEnumeratorDidFindFileInDirectory")) {
$this->delegate->directoryEnumeratorDidFindFileInDirectory($this, $file_name, $parent_path);
}
}
So, in this case, if the delegate cares about when the DirectoryEnumerator finds a file, it implements directoryEnumeratorDidFindFileInDirectory(), otherwise, it doesn't. This technique allows you to couple disparate classes very easily and suprisingly naturally. The lack of explicit typing does allow for bugs to creep in, though (what happens, for example, if you mispell "directoryEnumeratorDidFindFileInDirectory" in the delegate?).
The biggest problem with prototyping Objective-C in another language is its out-in-left-field approach to constructors. Objective-C "constructors" are just plain weird.
A constructor is a promise on the part of the programming language that you can allocate memory for an object and initialize that object into a consistent state in a single step. That way the programmer never has access to the uninitialized object. When an object has a superclass, the constructor for the super class is called first and then the object's own constructor is called. The idea is to make sure that the object is a valid instance of the superclass before turning it into an instance of the subclass.
Objective-C doesn't really have constructors, per se. Instead, a class has two methods, one for allocating memory and another for initializing it, that are called in succession. Because the initializer is just any old method, the programmer has to make sure that the superclass' initializer is called before it does any initialization of its own. This opens up a potential problem, though: what if the constructor in the superclass has a method that has been overriden by the subclass? The subclass' version of the method expects that the object has been initialized — but the subclass' initializer hasn't finished yet. This could lead to an error.
Modern programming languages, such as Java, solve this problem by considering any object as an instance of the class whose constructor is currently executing. That is, an object is guaranteed to run its own versions of methods called in its constructor, even if they are overriden in a subclass. Objective-C can't do this, of course, because its initialization occurs in a regular method.
PHP offers constructors but dispatches methods dynamically within them. For example, the following PHP:
<?php
class Foo {
/* This is Foo's constructor */
function Foo() {
$this->boo();
}
function boo() {
echo "Foo says boo!\n";
}
}
class Bar extends Foo {
/* This is Bar's constructor */
function Bar() {
echo "Done initializing Bar\n";
}
function boo() {
echo "Bar says boo!\n";
}
}
$bar = new Bar();
?>
results in:
Bar says boo!
Done initializing Bar.
You can imagine that if Bar's version of boo() relied on the object being initialized, bad things would happen. In contrast, the equivalent program in Java would output:
Foo says boo!
Done initializing Bar.
It turns out that dynamic dispatch during initialization is quite useful. It allows you, for example, to write a "skeleton" constructor in the super class and have the subclass fill in the details. I rely on this quite a bit in Objective-C, and it is nice to be able to design for it in my PHP prototypes.
Unfortunately, Objective-C "constructors" have other facets that PHP constructors can't emulate — indeed, there are many important aspects of Objective-C that don't really have an analogue in PHP.
Objective-C's syntax for method calls is perhaps its most remarked-upon feature. It is also quite different from any other language I have worked with and takes some getting used to. A method is called as follows:
NSColor *newColor = [color blendedColorWithFraction: 0.5 ofColor: anotherColor];
(For comparison, in Java this might be expressed as
color.blend(0.5, anotherColor), whereas in Perl we might have
$color->blend(0.5, $anotherColor)).
Here color is the target (or receiver) of the method with name blendedColorWithFraction:ofColor while 0.5 and anotherColor are the parameters for the method.
Notice that the parameters aren't passed by keyword (or key-value) like in Python. Instead, the paramaters are passed inline within the method name. I like to think of this as a "fill-in-the-blank" or Mad-Lib: a method name is a phrase with certain parts missing. In order to invoke the method, you fill in the missing parts.
It is standard practice to indicate something about the meaning of each parameter before its place in the method name. So, in the invocation of the method from the PHP delegation example above, we would have:
[delegate directoryEnumerator: self didFindFile: file_name inDirectory: parent_path];
This is a bit like Hungarian notation but without the Hungarian. Many people find this quite unwieldy, but I think it is quite useful. When you memorize a method, you have to memorize the order and type of the arguments anyway — in this style that information is just encoded in the method name. I find thinking of a method as a phrase rather than as a name makes a lot of sense. It makes unfamiliar code a lot easier to read, too. PHP doesn't have this naming convention, so prototyped method names have to be munged (I simply remove the colons, which is potentially ambiguous, but there are other more reliable techniques).
Another problem with prototyping applications in PHP is that PHP doesn't support threads. Often times, the most difficult part of designing a (non-GUI) application is ensuring consistent state and scalability across concurrent accesses. Without threads, there is no good way to prototype concurrency. On the other hand, for many projects, it may be overkill (and a major distraction) to introduce threading into the prototype.
In any event, PHP has just the right combination of simplicity, power, and crappiness to prototype OO projects.