I had a good reminder today of what Erik Naggum was talking about when speaking with a co-worker. He was trying to come up with a "good" solution to a Perl problem, so I had him describe it to me. It turns out that he has an object, which may or may not contain the attribute he's looking for. If it doesn't have it, the object has an attribute referring to another object. This other object, in turn, may or may not have the attribute he's looking for, and also has a reference to another object; this repeats until the "next object" is null.
Astute readers will have recognized this as a basic linked list.
I figure, okay, he hasn't been programming in a long time, so we'll mentally walk him through it. First, a quick nudge to see if he can remember his basic CS from a long time ago: "Why don't you write something that will just recurse through that list?" He nods, but the eyes, they don't have it. He goes away to think about it for a while, and then we wind up on a conference call in a meeting room. While the person we're calling is talking, he's quickly jotting down on the board:
O -> O -> O -> ...
I think, okay, he has the mental idea now, because he's diagramming it correctly. We talk a bit more, and he's obviously trying to come up with a way to iterate over the list. Once again, I suggest a simple recursive function (because that's natural to me, goddamnit, I don't care what you iterative programmers say), and quickly psuedocode something up for him:
function blah(o) if !o: return null if o->whatImLookingFor: return o->whatImLookingFor return blah(o->nextObject) found = blah(myList)
He looks at it, and appears puzzled. This appears to be a new construct to him, and he asks a few questions that confirm this. "But it'll just keep calling itself and looking at the same object all the time, won't it?" My first psuedocode example unfortunately used similar variable names in both the "mainline" and the function itself, but after renaming things, he still didn't seem to understand. Ah! Local vs. global scoping rules, maybe? So I suggest that, in Perl, you'd have something like my ($o) = @_; as the first line of that function. He still doesn't get it, and grunts something about just dumping the objects and grepping for what he's looking for. He just couldn't make himself look at the "CS" solution, because it didn't fit what he was expecting from Perl: a quick hack that did what he wanted without having to think too hard about it.
Systems administrators who spend to much time with "qwiky" languages like Perl are doomed to forget everything they ever knew about Computer Science. I'm convinced of this now. You might think I had this conversation with a newbie programmer or someone who whipped up scripts now and then, but you'd be wrong; this is a fellow who did software development professionally, and moved into systems administration later in his career. He's no idiot.
(I liken the problem to "l337 sp33k". I've known colleagues who could carry on a perfectly professional conversation face-to-face, but the moment they sit down at a keyboard, they immediately regress to "OMG r u 4 r34l?!" and, setting aside perceptions, they actually behave dumber while doing this. Perl has a similar effect on programmers; in the end, you end up with something that's a tangled web of spaghetti code and system() calls, getting the job done but disgusting anyone who has to look at it. Sort of like reading, "omg u pwn3d that bug, yo!". I wonder when someone will spec a programming language called "l337"...nevermind, Google to the rescue. Ye ghods.)
Postscript: yeah, I probably should have given him an iterative version of the pseudocode. Something like this:
function blah(o): while o: if o->whatImLookingFor: return o->whatImLookingFor o = o->nextObject return null
Just as simple, conceptually. Maybe some people have trouble wrapping their heads around recursion, but it's always seemed like a very straightforward idea to me.