Over at the CodeSnipers site, Rusty Divine is running a multi part series on design patterns. He recently posted a look at the Singleton design pattern, with some Java and C# based examples.

I wanted to show that same pattern using Ruby:

require 'singleton'
class Hermit
  include Singleton
end

That's it.

Using Ruby's powerful Mixin functionality, we bring the singleton code into our class definition. This automatically makes our class's new method private, and give us an instance method we can use to get our object:

irb(main):005:0> a = Hermit.new
NoMethodError: private method `new' called for Hermit:Class
        from (irb):5
irb(main):006:0> a = Hermit.instance
=> #<Hermit:0x20a1cc>

That was easy, wasn't it?

Note, Jan 10th 2005 -- I've turned this and the "anti-anti-hype" post back on. Please see the note at the top of anti-anti-hype. -steve

Gregory wrote:
> Steve, I'm just suggesting not putting fuel on a fire most Rubyists
> never intended to start in the first place.
>
> There is no need for a crusade or jihad here, on either side of the fence.
>
> This post just seems to be painfully biased with the expressed intent
> of bashing Python. That's just not cool.
>
> Pythonistas are not all tax collectors.

Yes, yes, I know how my "anti-anti-hype" post must have felt. Given that I'm like 600 dog-years old, I sometimes forget the context is missing when I post. I'm going to try once more to explain where I was coming from in that post. If this attempt fails, it's really no big deal -- I can certainly stick to technical blogs.

Incidentally, I'm going to talk about several languages, and eventually make my way back to Ruby at the end. Hang in there.

I think there are some issues we don't often talk about that have a direct impact on our lives as programmers. Like politics, they're tricky to talk about without arousing great, fiery passions. I'll be talking about some of them today. Why would I do that?

Well, first of all, let's get my agenda out in the open. I'm a programmer, and like you, I love building things. And ideally I'd like to build things in my favorite programming language, which happens to be Ruby -- but only by a slim margin, because I love several other languages too, including Python, Scheme, Lisp, the "D" language, C (but not C++), and various others. I like a lot of languages a little bit, and there are only a few languages that I don't like very much.

As it happens, Python is my second-favorite language.

Yup, that's right. You heard me properly. I love Python and I think Guido is brilliant. Matz, too. Those guys are just amazing.

My agenda is really simple: I would like to write the majority of my code, at home and at work, in a great programming language.

Well, it's simple to state. It's not simple to *do*, for lots of complex and rather painful reasons that should be non-issues, but they're not. Let's look at them a little, and hopefully it will shed a little light on my "uncool" post.

Death of a beautiful language

I watched Smalltalk die.

I wasn't particularly invested in Smalltalk at the time, but I had done some programming in it. Smalltalk was (and still is) a superb programming language. And it died after I learned it.

There are some Smalltalk enthusiasts out there who will point to Squeak and other Smalltalk enclaves, and claim it's not dead. This is an important point. Chances are, you don't take Smalltalk very seriously. It's not on your radar. You don't think you'll ever need to learn it. So when I say "I watched Smalltalk die", to you it sounds like ancient history.

To lots of people, though, especially the ones who loved Smalltalk deeply and whose very livelihoods depended on its commercial success, the failure of Smalltalk is a very painful subject. It's not boring ancient history. It still hurts them, deeply, and they even maintain hope that it may someday experience a glorious return to popularity.

This pain they feel, which you probably do not, is really close to the heart of our discussion. Hurt feelings are why these issues are so hard to talk about. It's very easy for you to say something insensitive about Smalltalk, *especially* if you don't know the language. You can take one look at it and say: "looks dumb", and you've just made someone mad.

What's really hard is that some people are just mad about Smalltalk in general. You can say anything at all about it, and simply bringing the subject up will have made them angry.

Regardless of whether Smalltalk is really dead, or merely a wounded bear in deep hibernation, I think it's clear that Smalltalk is not having a direct impact on the programming world today.

Smalltalk has lots of indirect impact, of course -- for instance, Ruby inherits a great deal from Smalltalk; all OO languages do to some extent, but Ruby more than many. But you can't walk into an ordinary computer bookseller and expect to find more than a couple of Smalltalk books. And if you want to get a job as a Smalltalk programmer, you will probably have to travel far, and you likely won't have much say in the kind of work you get to do. Smalltalk has retreated into a relatively small set of domains, at least for now.

What killed Smalltalk, anyway? I've read lots of analyses, and talked at length with some of the key players. The consensus seems to be that Java killed Smalltalk. And it did so rather decisively. Have you ever watched the short animated film "Bambi Meets Godzilla"? That's pretty much what it feels like now, although it actually happened over a period of several years.

There were certainly other factors involved. Smalltalk had an unusual all-in-one image model, where it acted like your OS, hosting the language, IDE, and application environment all in one binary. That is widely considered unpopular in retrospect, but the irony is that it's not really much different from the JVM. Smalltalk was commercial, and required user licenses; Java was commercial, but gave end-user licenses away for free. But they were really pretty similar, and one wound up being far and away more popular than the other.

You can argue that Smalltalk would have failed fair and square, without Java, but I think most people agree that Java had a LOT to do with Smalltalk's failure. And it wasn't a quiet thing, either. Millions of dollars were at stake. There were two large commercial Smalltalk vendors, and a bunch of unhappy about-to-be-ex-Smalltalk programmers, and there were lots of howls of protest at how Java, an "obviously" inferior language, had unfairly stolen a market that rightfully belonged to Smalltalk.

It all quieted down eventually, and to a lot of you, Smalltalk probably feels like a niche academic language that never had any real popularity.

I think Java coming along and smooshing Smalltalk had a lot to do with marketing. It's not the only factor, of course. Timing was a factor in various ways. Syntax and static typing were both factors, because Java deliberately went after disenchanted C++ programmers, which wasn't a bad strategy at all. And Java had some genuine innovations that helped, too.

But it was marketing that tied all these things together and helped Sun build a worldwide community of millions of Java programmers.

Java wasn't really offering anything that Smalltalk hadn't already been doing for years. (Where have we heard that argument before?)

Love and Money

It seems to me that there are two major contributors to language flamewars.

The first is that most programmers don't like to learn new languages. I don't know why, but true polyglots like me seem to be comparatively rare, maybe 5%-10% of the programmer population. Most folks apparently prefer to master one language and stick with it for life.

The second is economics. Money motivates most decisions in the end. Companies need to make money, programmers need to get paid. You know all the old sayings: time is money, business is war, money (or love) makes the world go 'round, all's fair in love and war.

Programmers fall in love with their languages, so you've got two of the biggest forces in the world at play here: love and money, mixed with either fear or laziness. Is it any wonder people fight over languages?

Well... sort of. It seems like people should be able to use whatever language makes them most happy. But in practice, you can only use your favorite language if it happens to be C++, Java, Perl, or whatever language(s) your employer has decided are the "official" languages. Most technical employers have a relatively small set of official languages, and you're forbidden from using any others. There are a few odd things about this situation.

One is that most companies couldn't care less about programming languages -- all they want is to get their products built. It's always the engineers who impose the language restrictions. They're not restricting themselves, of course; it's a situation where engineers are governing other engineers by decree, within the same company. I've heard all the reasoning, and it still seems a little odd to me.

Another other odd thing is that most companies are using anywhere from 15 to 40 programming languages, but they only officially recognize two or three of them. They'll claim they're a Java/C++ shop, but have huge gobs of shell-script, awk, PHP, Perl, JavaScript, Tcl, emacs-lisp, vim-script, excel macros, pl*sql, and other languages threaded through their tools, databases, build systems, and so on. Maybe this is less true at Windows-based development shops.

And one last odd thing is that programmers often have to learn at least one new language when they arrive at a new job, but they never have any trouble. Programmers only think learning a new language is hard. When it's a job requirement, it happens amazingly fast. Programmers are pretty smart people, you know.

So why do they fear languages so much? You'd be amazed at how much resistance the "old guard" of a company will offer if you try to use your favorite language, and it's not on the approved-list. The "old guard" could even be 23-year-old CS grads that have just made a successful startup. "Old" here just means "first".

I've heard their arguments for 20 years. Don't use C++, it's slow (my first company). Don't use Java, it's slow (my second and third.) Don't use Python, it's slow and has that whitespace thing. (All but my most recent.) Don't use Ruby, it's weird (90% of all companies). Language diversity is bad. What if someone has to debug your code in the middle of the night and they don't know that language? (every company, even those that don't work in the middle of the night) Don't use other languages; we don't hire for those skills. We don't trust those languages. We've invested in Fortran or Cobol or C++ or Java or whatever. No, no, no.

"No" always comes from engineers. You build something cool and popular, and your CEO will love you for it. She won't care if it's written in Intercal, as long as it works and your team can keep it working. So why do the engineers care so much? Who knows. I think it's often ego -- they think of themselves as a great Java programmer, or an important Perl luminary, or a famous Python person, and they let their perceived self-image influence other peoples' technical decisions. Whatever the reason, it's a very real force in the workplace, one that plays a large role in the language wars we see on the internet.

Because, hey, if enough companies are *already* using your favorite language, then the problem still exists -- but not for you!

Return of Godzilla vs. Bambi

I programmed in assembly language for 5 years at Geoworks; maybe that's why I love all languages a little. Then C/C++ for a while, and then a long 7-year stint with Java.

After 2 or 3 years with Java, I discovered Jython, which is pretty nifty port of Python to the JVM. I'd been doing a lot of my scripting and auxiliary work in Perl. This is before it had ever occurred to me, still being pretty new, that one language could actually be suitable for most programming tasks. Java's not very good at many things Perl is good at, and vice-versa, so I had a big mixture of Java and Perl.

I talked in my anti-anti-hype blog a little about Perl's marketing. It was world-class, and for a while I even thought I liked Perl. The marketing was so powerful that I just took it for granted that I liked Perl.

Jython was a breath of fresh air, and I started wishing I could replace all my Java *and* Perl with it. Development had stopped on it, though, so it naturally led me to Python. For at least three years, Python was my favorite language, but I was heavily invested in the JVM, so I had to settle for Jython most of the time. It sure was fun, even though it was an old, relatively unsupported version of Python.

During those years, I wondered why Python wasn't as popular as Perl. It seemed like a much stronger language than Perl. That's just my opinion, of course, and there were certainly things I missed from Perl, so I'm not claiming that Python is the be-all, end-all of language design. But it seemed like the best thing out there.

Why wasn't it more popular? It seemed to be getting crushed by marketing forces -- by fiery-eyed Perl zealots who went around and gained converts, one at a time. Perl was acting like a virus, and spreading rapidly, while Python sort of limped along, growing much more slowly. Richard Gabriel, of course, had already pointed out that C and Unix were virus-like in his famous short essay, The Rise of ``Worse is Better''.

Let's be careful here: I believe Python has failed so far, and lots of people have jumped to say that Python "beat" Perl. Sure it did, in lots of quality-related ways. But the most immediately relevant metric to me is popular success in the commercial marketplace, because (remember my agenda?) I want to write my day-to-day code in a great language. I can't just tromp into most companies and announce I'm going to be writing in Python; they'd lynch me. So to this extent, Python has failed. And I really, REALLY wish it hadn't. Because unlike when it happened with Smalltalk, I was invested this time around.

Because Python was my favorite language, I read lots of Python books, and wrote lots of Python code, and lurked on Python newsgroups, and basically soaked up the culture. And over a few years, I developed my own pet theory as to why Python has (so far) failed commercially.

Culture

I know you're gonna hate this part, but I'm going to talk a little about culture. Culture is very real. It matters every bit as much as love or money.

French waiters in Paris, on average, behave very, very differently from Japanese waiters in Tokyo. It is absolutely undeniable, and the difference is striking. I've spent plenty of time and eaten at plenty of restaurants in both places.

Once I was dining with a friend, and he whispered across the table: "I'd ask for some salt, but I think our waiter would kill us." Which country do you think was I in?

French waiters are not good or bad people, nor are Japanese waiters. They're just doing what's acceptable in their culture. But their cultures are very, VERY different. Waiting tables usually has a distinct subculture in any country, so I'm really just comparing the subcultures of French waiters in Paris and Japanese waiters in Tokyo.

I'm going to go out on a limb here, and say that I found French waiters in Paris almost terrifying. They huffed and puffed and stomped and glared and slammed the food down and were so comically over-the-top rude that it *had* to be an act, since my friends and I never did anything but politely sit down and point tentatively at menu items.

In contrast, I've seen Japanese waiters go to almost comical lengths to try to accommodate the requests of drunken people on business trips, to the point where I started feeling really un-proud to be an American. Japanese customer service practically defines world-class.

OK, I hope we've established that cultures differ, and they have an enormous impact on your experience with people in that culture.

I think it should be obvious to you that programming languages have subcultures, too. The Perl culture is very different from the Python culture, and both are very different from Ruby culture.

The Python culture has a lot going for it. I was pretty immersed in it. But over time, as I wondered why Python wasn't becoming an overnight phenomenon, I started noticing some cultural behaviors in the Python community that I feel may be partly responsible. This is, of course, just my own opinion, endorsed by nobody.

I pointed out some of these behaviors in my anti-anti-hype blog, and of course some people (Rubyists, Pythonistas, innocent bystanders) assumed I was Python-bashing, because they didn't watch Smalltalk die, and they didn't have the context I'm giving you now.

In reality, I'm actually just flat-out disappointed that Python never captured Perl-like marketplace success -- and if you've been with me so far, you'll know this has real economic ramifications in terms of ability to write Python code in the workplace. And worse, it appears to be an avoidable problem: I think there are certain accepted practices in the Python world that are materially harming Python's adoption in the commercial marketplace.

I could spend a long time justifying each of my claims from "anti-anti-hype", but let's just focus on one of them: the tendency to label people as "incorrect". It's just an annoying habit, but one that can easily drive a potential new user away. It's a cultural habit, just like stomping and glaring and saying "psh!" loudly is a cultural habit among waiters in small restaurants in the Quartier Latin district of Paris.

The fact is, it doesn't take very much searching to find examples of this labeling. For instance, Recipe 1.7 of the Python Cookbook ends with a discussion around attributes versus items, and claims that many newcomers to Python "desire confusion", especially if they've come from a JavaScript background.

That seems kinda mean to me. If a programmer is genuinely confused, then fine, they're confused, although there's no need to harp on it. But if lots of programmers are asking for a way to solve problems in a way they're used to, then labeling them as "confused" (a word that dictionaries varyingly define as baffled, perplexed, or unable to think with clarity or act intelligently) seems kinda harsh. Doesn't it?

Similarly, in Chapter 5 of the "Jython Essentials" book, during a discussion of Python's class system, it says: "Sometimes people erroneously see the need to explicitly specify the instance in the method argument list as evidence that object-oriented programming is somehow 'tacked on' to Python."

"Erroneously"? Gosh, this issue seems like a matter of pure opinion, not a fact that one can be either correct or incorrect about. How can an opinion be erroneous? Well, it's a cultural thing. If you have a culture of labeling differing opinions as incorrect, then an opinion can easily be considered erroneous.

There used to be an entry in the Python FAQ, which they removed a year or two ago, that said something along the lines of "Am I allowed to suggest changes to the language?" and the answer was a terse: "No." I can't remember the exact wording, but I found it pretty jarring, and it was there for years before getting cleaned up.

These little things add up, and there are lots to be found. You may not notice them at all when reading Python discussions or documentation. I noticed because I was actively looking for people who had tried Python and decided not to use it, and reading their write-ups and opinions. Often as not, they said they felt rebuffed, or felt the community wasn't welcoming them, or some other touchy-feely type thing that didn't seem like it should have mattered at all. But there it was: a pattern had emerged.

Are all Python folks to blame for this? Of course not. Most Pythonistas people are really nice, warm, genuine, honest, smart people.

But a culture is a culture, and it has a big impact, like it or not. If the initial experience results in frequent enough culture-shock, it'll drive a lot of potential new users away.

Feel free to draw your own conclusions about why you use can Perl at most companies, but Python at relatively few. I've given you my take on it, and even if it's not the whole story, I honestly think it's a factor. There's more to marketing than glossy banners and shapeless cartoon mascots. Marketing can work all the way down to the level of individuals in one-on-one interactions.

In 10 years, I really don't want to be able to say: "I watched Python die". There's plenty of room for maybe 5 to 8 really huge languages in the marketplace. I think Ruby's going to be up there soon, and frankly I'd more than welcome Python up there too.

In the meantime, though, I've been half-assuming that you can't change a culture -- that once it's set, it's set. I hope I'm wrong. But my assumption is one of the biggest reasons that I finally switched to Ruby, just recently, over the summer, and committed to it for the forseeable future. (I'm guessing 5 to 10 years.)

Ruby

The worldwide Ruby culture is the warmest and friendliest I've seen in my long history with programming languages. And Ruby is a sweet language. Other people seem to agree, and are taking steps to market it, which is getting them labeled -- rather rudely, it would seem to me -- as "hyper-enthusiasts". As far as I can tell, Ruby is doing what I wanted Python to do a few years ago, so I've finally learned Ruby and have switched most of my development over to it.

Both languages have a long way to go before they catch up with Java in terms of tools, IDEs, books, performance, threading stability, and tons of other stuff. I wanted to make a reasonably educated bet, and choose the language I think is going to be bigger, so it'll work well for me, and so I won't have to fight so hard to use it in my job.

It wasn't hard to learn Ruby. In fact after a few days with it, Ruby felt as comfortable as languages I'd been using for years. I've really been enjoying it. It has a few warts; all languages do. No biggie. It looks as if Matz is intent on fixing them in Rite.

I don't know if I like it more than Python and Scheme. I like it at least as much as those languages, certainly. But Ruby's my favorite (as in "preferred") language now because I can see the trajectory it's on, especially now with Rails, and I believe it's going to be the Next Big Thing -- a Java-like phenomenon. So did Bruce Tate when he wrote "Beyond Java". So do James Duncan Davidson, Dave Thomas, Martin Fowler, and many other people who are a heck of a lot smarter than me. You'd think they're on to something big, wouldn't you? I do.

Java-like worldwide adoption really matters. Without that level of mass-market adoption, Ruby won't get the tools, stability, and CPAN-like library selection that it needs in order to compete with Java and Perl. It's a chicken-and-egg problem that all languages face, and Ruby stands a chance of succeeding where Smalltalk, Python, and other great languages have (to date) failed.

I see a lot of Rubyists worrying that Rails is stealing the show. Geez, folks, LET it steal the show. Talk about a free ticket for Ruby success. Java Applets were a way to get Java in front of a million or so programmers, ultimately allowing the Java platform to succeed in all sorts of domains that it might never have seen without the initial "killer app" of Applets.

We live in a world where culture matters, economics matter, and marketing hype matters. They are very real forces that directly affect our quality of life as programmers. You ignore them at your peril, a lesson learned by so many almost-forgotten languages that were stomped by marketing hurricanes like Java and Perl.

I really wanted Python to succeed, and I still wish them the best, but I think they're ignoring marketing. I really want Ruby to succeed, so I get a bit miffed when I hear famous people like Bruce Eckel making uninformed generalizations about both Ruby and the folks who are working hard to make it successful. I think Pythonistas should be focusing on doing the same -- working to make Python successful. I do think it will take a minor cultural adjustment on their part. And they need to start accepting hype as a natural part of the world we live in, a requirement for cutting through the noise. But I think they can do it.

With this context, does my "anti-anti-hype" post start to make a bit more sense? Try re-reading it and see.

If not, well, you can't please everyone. I'm old enough not to mind.

Note, Jan 10th 2005 -- I removed this post after receiving enough angry letters about it to make me feel bad for having written it. In the 10 days or so since then, I've received angry letters telling me that I'm rewriting history by turning it off, and so on. It's a lose-lose situation for me. At the risk of becoming the most hated person in blogdom, I'm turning it back on. Please make sure to read the follow-up, "Bambi Meets Godzilla", before sending me your angry flames. Thanks. -steve

Everyone's buzzing about Bruce Eckel's "anti-hype" article. I hope the irony isn't lost on him.

The thrust of Eckel's article appears to be that hyper-enthusiasm is diminishing the Ruby camp's message, and it's spoiling a good gentleman's argument. Those darn hyper-enthusiasts are focusing relentlessly on how cool Ruby is and how much they like it, when what's really needed here is a balanced, objective, neutral, moderated, standards-based, point-by-point, academic discussion of Python vs. Ruby, in which we can all make well-informed decisions, and may the best language win, as long as it's Python.

Python folks never really did understand marketing.

I'm surprised we need a history lesson here; we've all been through this so many times before. But let's look once again at the basics of language adoption.

First, inferior languages and technologies are just as likely to win. Maybe even more likely, since it takes less time to get them right. Java beat Smalltalk; C++ beat Objective-C; Perl beat Python; VHS beat Beta; the list goes on. Technologies, especially programming languages, do not win on merit. They win on marketing. Begging for fair, unbiased debate is going to get your language left in the dust.

You can market a language by pumping money into a hype machine, the way Sun and IBM did with Java, or Borland did back with Turbo Pascal. It's pretty effective, but prohibitively expensive for most. More commonly, languages are marketed by a small group of influential writers, and the word-of-mouth hyping extends heirarchically down into the workplace, where a bunch of downtrodden programmers wishing they were having more fun stage a coup and start using a new "forbidden" language on the job. Before long, hiring managers start looking for this new language on resumes, which drives book sales, and the reactor suddenly goes supercritical.

Perl's a good example: how did it beat Python? They were around at more or less the same time. Perl might predate Python by a few years, but not enough for it to matter much. Perl captured roughly ten times as many users as Python, and has kept that lead for a decade. How? Perl's success is the result of Larry Wall's brilliant marketing, combined with the backing of a strong publisher in O'Reilly.

"Programming Perl" was a landmark language book: it was chatty, it made you feel welcome, it was funny, and you felt as if Perl had been around forever when you read it; you were just looking at the latest incarnation. Double marketing points there: Perl was hyped as a trustworthy, mature brand name (like Barnes and Noble showing up overnight and claiming they'd been around since 1897 or whatever), combined with that feeling of being new and special. Larry continued his campaigning for years. Perl's ugly deficiencies and confusing complexities were marketed as charming quirks. Perl surrounded you with slogans, jargon, hip stories, big personalities, and most of all, fun. Perl was marketed as fun.

What about Python? Is Python hip, funny, and fun? Not really. The community is serious, earnest, mature, and professional, but they're about as fun as a bunch of tax collectors.

One could write a fat book about this, but just to give you the flavor, consider what happens when you type "python" at a command prompt. It fires up a little interactive interpreter. At the prompt, if you type "quit", it responds with 'Use Ctrl-D (i.e. EOF) to exit.'

Well that's not very nice, is it? It *knows* you want to quit, even going so far as to call you an EOF, whatever that means. (Yes, you and I both know, but is it really the right thing to show to a beginner? Hardly.) Why didn't it just quit, then?

If you were to bring this issue up on a Python newsgroup at any time in the past 10 years, someone would tersely have instructed you to go look at the FAQ. Or they'd have explained that having 'quit' quit would be a strict violation of the semantics of the REPL, which has no a priori knowledge of English, and as Ctrl-D is universally recognized as the EOF char on most terminal emulators, excepting of course broken ones on win32 and VAX platforms, and the interactive shell's clean design allows the interpreter to treat the input as if it were coming from a file or similar stream, blah Blah BLAH, ergo, the current behavior is correct, quod erat demonstrandum.

Never mind that it's patently obvious that "quit" should just quit the frigging shell, semantics be damned. They don't care a whit, because they're focused on the "right thing" at the expense of the user experience. There's an old adage for this; it's called "missing the forest for the trees."

Of course it's just as difficult to figure out how to exit the Perl shell, if not more so. But if you were to bring it up on a mailing list or newsgroup, some nice Perl person would come along, eager to show you how to add one more snippet of job security to your lineup of Perl folklore, and would spend an hour explaining how cool it is that you can quit the shell with a single keystroke, one that works in other Unix commands as well, and then maybe show you how to hack the Perl binary so that "quit" also exits the shell for you. The difference is huge: both shells have that crappy misfeature, but Python folks will bore you with justifications while the Perl folks excite you with marketing.

Pedantry: it's just how things work in the Python world. The status quo is always correct by definition. If you don't like something, you are incorrect. If you want to suggest a change, put in a PEP, Python's equivalent of Java's equally glacial JSR process. The Python FAQ goes to great lengths to rationalize a bunch of broken language features. They're obviously broken if they're frequently asked questions, but rather than 'fessing up and saying "we're planning on fixing this", they rationalize that the rest of the world just isn't thinking about the problem correctly. Every once in a while some broken feature is actually fixed (e.g. lexical scoping), and they say they changed it because people were "confused". Note that Python is never to blame.

In contrast, Matz is possibly Ruby's harshest critic; his presentation "How Ruby Sucks" exposes so many problems with his language that it made my blood run a bit cold. But let's face it: all languages have problems. I much prefer the Ruby crowd's honesty to Python's blaming, hedging and overt rationalization.

As for features, Perl had a very different philosophy from Python: Larry would add in just about any feature anyone asked for. Over time, the Perl language has evolved from a mere kitchen sink into a vast landfill of flotsam and jetsam from other languages. But they never told anyone: "Sorry, you can't do that in Perl." That would have been bad for marketing.

Today, sure, Perl's ugly; it's got generations of cruft, and they've admitted defeat by turning their focus to Perl 6, a complete rewrite. If Perl had started off with a foundation as clean as Ruby's, it wouldn't have had to mutate so horribly to accommodate all its marketing promises, and it'd still be a strong contender today. But now it's finally running out of steam. Larry's magical marketing vapor is wearing off, and people are realizing that Perl's useless toys (references, contexts, typeglobs, ties, etc.) were only fun back when Perl was the fastest way to get things done. In retrospect, the fun part was getting the job done and showing your friends your cool software; only half of Perl's wacky features were helping with that.

So now we have a void. Perl's running out of steam for having too many features; Java's running out of steam for being too bureaucratic. Both are widely beginning to be perceived as offering too much resistance to getting cool software built. This void will be filled by... you guessed it: marketing. Pretty soon everyone (including hiring managers) will see which way the wind is blowing, and one of Malcolm Gladwell's tipping points will happen.

We're in the middle of this tipping-point situation right now. In fact it may have already tipped, with Ruby headed to become the winner, a programming-language force as prominent on resumes and bookshelves as Java is today. This was the entire point of Bruce Tate's book. You can choose to quibble over the details, as Eckel has done, or you can go figure out which language you think is going to be the winner, and get behind marketing it, rather than complaining that other language enthusiasts aren't being fair.

Could Python be the next mega-language? Maybe. It's a pretty good language (not that this really matters much). To succeed, they'd have to get their act together today. Not in a year, or a few months, but today -- and they'd have to realize they're behind already. Ruby's a fine language, sure, but now it has a killer app. Rails has been a huge driving and rallying force behind Ruby adoption. The battleground is the web framework space, and Python's screwing it up badly. There are at least five major Python frameworks that claim to be competing with Rails: Pylons, Django, TurboGears, Zope, and Subway. That's at least three (maybe four) too many. From a marketing perspective, it doesn't actually matter which one is the best, as long as the Python community gets behind one of them and starts hyping it exclusively. If they don't, each one will get 20% of the developers, and none will be able to keep pace with the innovation in Rails.

The current battle may be over web frameworks, but the war is broader than that. Python will have to get serious about marketing, which means finding some influential writers to crank out some hype books in a hurry. Needless to say, they also have to abandon their anti-hype position, or it's a lost cause. Sorry, Bruce. Academic discussions won't get you a million new users. You need faith-based arguments. People have to watch you having fun, and envy you.

My guess is that the Python and Java loyalists will once again miss the forest for the trees. They'll debate my points one by one, and declare victory when they've proven beyond a doubt that I'm mistaken: that marketing doesn't really matter. Or they'll say "gosh, it's not really a war; there's room for all of us", and they'll continue to wonder why the bookshelves at Barnes are filling up with Ruby books.

I won't be paying much attention though, 'cuz Ruby is soooo cool. Did I mention that "quit" exits the shell in Ruby? It does, and so does Ctrl-D. Ruby's da bomb. And Rails? Seriously, you don't know what you're missing. It's awesome. Ruby's dad could totally beat up Python's dad. Check out Why's Poignant Guide if you don't b'lieve me. Ruby's WAY fun -- it's like the only language I want to use these days. It's so easy to learn, too. Not that I'm hyping it or anything. You just can't fake being cool.

It appears that Microsoft is looking for people to work on IronPython and dynamic language support for the CLR.

Having Ruby apps run as native .Net code would be quite nice.

Found via Bill de hÓra

Recently, I starting an attempt to upgrade one of our critical pieces of software to a new underlying library revision, and it proving to be quite a challenge.

I’ll spare the details, but suffice to say it’s not pretty. One aspect I’m currently focusing on is a nice way to share data between modules, those already written and those yet to be written. Historically we’ve used IPC shared memory, which for ruggedly defined structures works very well. However, for dynamic streaming data, it doesn’t fare so well. Furthermore, I need a well defined interface - an abstract one, if you will, that works between various programming languages and toolkits.

Enter the filesystem. I recently discovered the fuse filesystem, and its Ruby counterpart FuseFS. Man oh man what a gem this little guy is.

Here’s a small snippet of what I’m currently accomplishing with FuseFS:

I have an application config file, which is stored in INI format like this:

[Group1]
key1=value1
key2=value2
...

And here’s a snippet of Ruby:

require 'fusefs'

$configfile = “/home/me/blah/myconfigfile.ini”

module INI
def self.read(filename)
inimap = { }
hdr = nil
File.open(filename).each do |row|
if row =~ /^\[(.+)\]$/
hdr = $1
inimap[hdr] = { }
elsif row =~ /^(.+)\=(.+)$/
hdr && inimap[hdr][$1] = $2
end
end
inimap
end
end

class SettingsDir < FuseFS::MetaDir
def initialize
super
confighash = INI.read($configfile)
confighash.each do |key,value|
mkdir(’/’ + key)
value.each do |key2,value2|
write_to(’/’ + key + ‘/’ + key2, value2+”\n”)
end
end
end
end
root = SettingsDir.new
FuseFS.set_root(root)
FuseFS.mount_under ARGV.shift
FuseFS.run

This code is simple. It reads an INI file, and creates a hash of hashes, and uses that to create a fake directory structure within the operating system. If I run this code, I can open a shell in another window and access this information via the filesystem:

tc@tc8 ~/configfs $ ls settings
Group1 Group2 Group3

tc@tc8 ~/configfs $ ls settings/Group1
key1 key2 key3

tc@tc8 ~/configfs $ more settings/Group1/key1
value1

As you can see, my hash of hashes is now available via the filesystem. Any application now has access to this abstracted information. From this point, it’s fairly trivial to implement a reverse setup, where when you write data to one of the files it saves that back to the hash, which in turn updates the INI file.

Granted, this is a mildly convoluted way to read and write to an INI file, but the point here is that we don’t have to worry about the INI file at all. This system would work for any backend, such as a SQL system or CSV file backend.

I’m pretty impressed so far, and I’ve only scratched the surface of what’s possible.

XML.com is featuring an article on getting started with Builder - an XML builder that was a part of Rails, but has become a full-blown project of its own.

So here’s the spiel: Object-oriented programming is all about sending messages. See, given some object, you don’t directly call methods; oh no, you send messages, like asking a favor; “Hey, object, do you think, like, you could, ....”, and the object gets to decide if it wants do you the favor or not. As a practical matter, the distinction between methods and messages varies among OO languages. For example, with Java, code using the standard message-invocation syntax will only compile if the message directly corresponds to a method.
foo.someMessage() // Compiler says the class behind foo must have a someMessage method
In Ruby, on the other hand, you are free to send pretty much any message you choose; the receiver does not need a message-method mapping in order to handle it.
foo.some_message # Code behind foo may or may not have a some_message method.
In the extreme case, you can have a Ruby class that handles all messages:
  class Pushover
    def method_missing( sym, *args )
      puts "Do I want to  #{sym.to_s.gsub( '_', ' ' )}?  Sure!" 
    end
  end

 po = Pushover.new
 po.buy_a_fake_rolex
 po.make_money_fast  
But even though Ruby affords this complete disconnect between messages and methods, most people code with the view that messages map to methods, or some well-defined set of message-based behavior. Maybe because coding pushover classes opens one up to too many risks. (But note that, in the right hands, you get great results .) I wonder, though, if part of the reason is the syntax itself, coupled with the phrase “object-oriented”. Alan Kay, creator of Smalltalk, has said .
Again, the whole point of OOP is not to have to worry about what is inside an object. Objects made on different machines and with different languages should be able to talk to each other—and will have-to in the future. Late-binding here involves trapping incompatibilities into recompatibility methods—a good discussion of some of the issues is found in [Popek 1984].
He’s also reported as saying, “Smalltalk is object-oriented, but it should have been message oriented.“ From a certain point of view, while objects handle the gory details, it’s the message exchange that’s really key. But objects always seem to be the center of attention; they always come first:
big_shot_object.poor_message_comes_last
In fact, you can’t even think about sending a message without first having an object. Or can you? Let’s see. First, we’ll need some new syntax. I’m not yet loopy enough to go invent my own language, so we’ll munge up Ruby code for our purposes. So this may not look as slick and clean as we might like. But, instead of the familiar
receiver.message( arg1, arg2 )
we’ll use flip things around a bit , and use
:my_message.>>( receiver1, receiver2 )
What this syntax means is, “Send the message my_message to all of the listed receivers.” And this
:my_message[ arg1, arg2, arg3 ].>>( receiver1, receiver2 )
means the same thing, but also passing arg1, arg2, etc. as message arguments. Oh, and before you wig out over funky syntax or the violation of the sanctity of Symbols or countless other details, know that much of what drives me to code (or do much of anything, for that matter) is an attitude of, “Gee, what happens if I push this button?” So there’s an element of the, um, unpolished and experimental in the mix. (Though I do expect that admissions of this sort merely prompt many readers to leer and start rubbing their hands as the imagination revs.)

Message-oriented Programming

What I wanted to explore was some form of message-oriented programming, where one could start with a message, then decide on a set of receivers. I thought of different ways to write this, and settled on using Symbols because I wanted something that afforded a decent literal syntax (e.g., “my string”, [ :my, :array ], 123). The idea of having to instantiate an instance of a Message class before using one seemed clumsy. (String literals were my first choice, but having to type all those quote marks got tiresome, and it tended toward the fugly side of things.) Symbols are also handy because they don’t actually do anything. There have very few methods, and are unlikely to pop up in unexpected places where the results of a classotomy might cause conflict. Adding new methods to the Symbol class seemed reasonably safe.

I picked the double-angle syntax as something of a visual indicator of transmission. My original version used block notation for passing arguments; this followed the list of receivers. But while writing this I decided it didn’t look very good, and, more important, didn’t seem to correctly convey its role. So I added the [] method. The basic goal was to have something that made some sort of visual sense. YMMV, blah blah blah, this is an experiment. Syntax aside, the neat stuff is what happens inside Symbol. In the basic case, something like
:message.>>( recv1, recv2 )
would be translated somehow into
recv1.send( :message )
recv2.send( :message )
(And I of course if there are any arguments involved they’d get passed along, too.) Of course, this raises a new issue: what is the return value, if any, of a cross-receiver message dispatch? I picked an array (and we’ll be getting to implementation details shortly). So, send a message to some number of receivers, and get back an array of response values.

Shooting in the Dark

I also wondered about possible use cases. If you already have a list of known receivers handy, then you might simply write a loop to do the message sending. But what if you wanted to send a message to some unknown set of objects, a set where the recipients are defined by some property or behavior? For example, imagine your application has all sort of IO-like objects floating around. You have no obvious way to locate them all, but you’d like to tell each of them to close, perhaps in preparation of some shutdown command.

My approach is to to allow the list of receivers to include Proc objects. Each Proc would need to define a conditional to determine if an object should be included in the receiver list. If, while processing the >> command, a Proc is encountered, the code loops over all objects in ObjectSpace, using the Proc to determine if an object qualifies as a receiver.

Code, please

So here we go:
class Symbol

  def []( *args)
    @args = args
    self
  end

  def >>( *objs )
    results = []
    arglist  = @args 
    objs.each{ |obj| 
      begin
        if obj.class == Proc    
          temp_ary =  select_by_proc( obj ) 
          results.concat(  self.>>( *temp_ary ){ arglist  }  )
        else
          results << dispatch( obj, arglist  )
        end

      rescue Exception
        results << $!.clone
      end
    }
    # Symbols stick around like a bad cold, so we need to reset the 
    # arg list after dispatching the message 
    @args = nil
    results
  end

  def dispatch( obj, arglist  )
    return obj.send( self.to_s, *arglist ) if arglist && ( arglist.size > 0 )
    obj.send( self.to_s )
  end

  def select_by_proc( pk )
    objs = []
    ObjectSpace.each_object do |obj| 
      begin
        objs << obj  if pk.call( obj )  
      rescue Exception
        warn "select_by_proc exception: #{$!}" 
      end
    end
    objs.uniq 
  end

end

Pass me the MOP, please

So let’s see an example. Earlier we looked at dynamic code that might a bit too easygoing. Now let’s look at some really gullible code:
 class Gullible
    def initialize( name )
      @name = name 
    end

    def herbal_cialas
      "Sure, I respond to herbal cialas!" 
    end

    def bank_account_details
       "@name: #{@name.intern.to_i}" 
    end
  end

Suppose then that there are a few gullible objects floating around:
 jim = Gullible.new( 'Jim' )    
 greg = Gullible.new( 'Greg' )
Now, if we decided to engage in some object-level spamming, we could really, um, mop up; we don’t need to know who these poor souls are, we just need to go find all objects that say they respond to messages about, say, herbal cialas, and ask them a favor, such as “Give me your bank account details”. Like so:
 poor_souls_accounts = :bank_account_details.>>( lambda { |o| o.respond_to?(  :herbal_cialas ) })
 p poor_souls_accounts # ["Greg: 17221", "Jim: 17229"]>
Now I just need to figure out spam filters. Shouldn’t be too hard.

Due to a Ruby Weekly News scripting hiccup, for a limited time only, you can check out news from February and July of 2005 over at http://rubyweeklynews.org.

I only realized this after asking James Edward Gray II when the dates for the ICFP were set to, and he mentioned that post had been from LAST year :)

Tim Sutherland responds on RubyTalk:

Oh dear.

Also, the "Active Record" and "Ruby on the mobile" threads were both
from July 2005.

My google-groups-screen-scraping-script-breaketh.

So if you are having that sinking feeling of deja vu... fear not, you weren't seeing things :)

Francis Hwang once posted an item about modifying Ruby’s require method so that you can load files over HTTP (or, really, pretty much any file transfer protocol).

It’s really quite clever. I think, though, that having to explicitly include the protocol scheme and path when calling require spoils half the fun.

My take on this is to alter Kernel#require so that it knows to look for requested files outside of the local file system.

# File: hyperactive-require.rb
require 'open-uri'

def require( resource )
begin
super
rescue LoadError
$:.each do |lp|
if lp =~ /http:\/\//i
begin
lp << '/' unless lp =~ /\/$/
s = open( "#{lp}#{resource}" ) { |f| f.read}
eval s
return
rescue; end
end
end
raise LoadError.new( "Cannot find '#{resource}'")
end
end

The trick here is that the load path must be given one or more Web addresses; these sites will then become just more places to look for code. Aside from that, client code does not need to know if some required file is local or remote.

A nice side-effect: No more installations. Well, maybe fewer, simpler installations. Distribute a basic script, define the appripriate URLs, and have it require the app libs as if they were local. You could also switch library version by changing LOAD_PATH URLs to fetch from different repositories.

Dangerous? Um, perhaps. But c’mon, it’s a new year. Live it up!

Besides, everyone knows how dangerous Ruby is . So dangerous that, in the spirit of the season, I even dreamed up Yet Another Ruby Motto.

Ruby: You'll Shoot Your Eye Out.

So let’s try an example and see if we lose an eye or something.

# File: trusted-sites.rb
# I trust these guys!
%w{
  http://www.30secondrule.com/living-dangerously/
}.each { |uri|
 $:.push uri
}

#!/usr/local/bin/ruby
# File: example.rb
# See if we can grab my vSocial.com RSS feed

require 'hyperactive-require'
require 'trusted-sites'
require 'vsocial'

vs = VSocial.new( 'jamesbritt' )
puts vs.rss

Whew! Scary, but no ocular mishaps. It's certainly no worse than running with scissors.

One side detail: The hyperactive-require code issues an HTTP request for a file with no extension, but it is likely that the actual source file on disk at the server will end in .rb. I used the MultiViews option with Apache2 to allow the server to return a disk file with a .rb extension even if the request URL did not specify that.

Oh, and note, too, that file requests going through an intermediary process opens the door for all sorts of entertainment. You could, for example, dynamically assemble the code returned, perhaps returning different versions based on the client’s IP address. Or have the server invoke a CVS or Subversion checkout to grab the latest code. Or send back a new version of Kernel#require or another set of LOAD_PATH URLs.

Or something. Just don’t hurt anyone.

    class OpenNode < OpenStruct
      include Enumerable
      def initialize(my_name, parent_name, children_name, name, options={})
        @my_children_name = children_name
        @my_parent_name   = parent_name
        @my_name          = my_name
        super(options)
        self.name = name
        self.send(@my_children_name) || self.send(:"#{@my_children_name}=",{})
      end
      def each(&p;)
        self.send(@my_children_name).values.each &p;
      end
      def add_child(klass,name,options={})
        options[@my_name] = self
        self << klass.new(name, options)
      end
      def <<(child)
        child.send(:"#{@my_name}=", self)
        self.send(@my_children_name)[child.name] = child.dup
      end
      def [](child_name)
        self.send(@my_children_name)[child_name]
      end
    end
Update: Thanks to steer on #ruby-lang for re-writing my messy each method

Symbols: They're numbers with a human face.

I really like Austin's earlier blog about Symbols and how they are just names.

I think the real confusion around symbols is three fold:


  1. The colon in the name

  2. The name Symbol

  3. How they relate to Strings

This will not come as a surprise to the experienced Rubyist, but for those in the crowd who are just learning, here is a bit of neat trivia for you to ponder.

Well, we all know that Fixnums (i.e. 1,2,3..) are objects in Ruby, right?
If you didn't, now you do!

So it's easy to do little tricks like


class Fixnum
def +(other)
self - ( -1 * other ) - 2
end
end

which will break your math and let you impress people who are new to open class systems.
(i.e. 4 + 9 == 11 with the above definition)

You could also do functional hacks like


class Fixnum
def squared
self ** 2
end
end

and get yourself 2.squared == 4

But one thing that I didn't think about until Gary Wright mentioned it on RubyTalk is how Fixnums can have instance variables!

class Fixnum
  attr_accessor :letter
end

('a'..'z').each_with_index { |letter, index| index.letter = letter }

now 0.letter == 'a', 1.letter == 'b', etc etc

Is this useful? I'm not really sure, to be quite honest. But it sure is neat!
See the discussion in it's original context at: http://www.ruby-forum.com/topic/50170

If you get any killer ideas for how to use such a feature, drop a comment here or there.

I wrote a couple of entries in this fancy new O'Reilly Ruby blog, and placed them in the "Opinion" category, which I evidently completely misunderstood to mean that it was for posting opinions.

Silly me. After this little follow-up, I'll endeavor never post an actual opinion to a public forum again.

It turns out that the little "Opinion" label is far more widely construed to mean either "Universally True Factual Statements" or "Lies", either of which appears to be grounds for getting Really Mad. It seems MovableType ought to have a little dropdown list for labeling your comments, providing convenient label options such as "Revenge", "Retaliation", "Retribution", "Flame Strike", and "Long List of Corrections". Ideally it would allow you to select multiple comment categories.

Note: I will receive angry comments for that previous sentence, and also for this one, and for everything else I write for the rest of my life that makes it online, advertently or not. So will you, if you ever make the profound mistake of choosing that "Opinion" category in a blog post. You'll also be quoted out of context all over the web, because apparently by choosing "Opinion", you are also claiming that you are a Leading Expert at whatever random thing you're talking about.

I've been a huge fan of Dave Barry's writing for almost 20 years, but as of last week I have newfound respect for the man. He often points out that Alert Readers regularly send him angry factual corrections and even hate mail about his humor columns. How did he put up with it for his whole career? I'll never know.

I've learned a few things in the past week. They are Universally True Facts! Ignore them at your own risk!

One is that if you ever opinionatedly claim that a specific group of people tends to be pedantic, something interesting happens: a whole bunch of people will pedantically inform you that you are incorrect. But they're not just from the group you mentioned; they're from everywhere. Pedants will materialize from every dimension to correct you. The corrections vary, of course. Some folks will just be negating what you said, occasionally colorfully. Some will announce that the *other* group (there's always another group; people love taking sides) is even *more* pedantic. A few will announce that I've slightly misused the term "pedantic", thus invalidating my entire article.

I'll vouch one of my last-ever opinions: namely, that "correcting" someone's opinion is automatically pedantic. Corrections inevitably overlook the basic problem that all communication is intrinsically ambiguous. Also, the shorter a statement is, the less universally true it becomes. So if you narrow in on any statement that someone makes, ignoring the surrounding context and failing to give some benefit of the doubt, you'll always be able to find things to correct. But chances are good that you'll also have missed their point.

Anyway, I've since realized that my opinionated claim wasn't broad enough. Almost any arbitrary grouping of people connected to the web will have a tendency to appear pedantic, because the most pedantic people are very eager to post corrections (by definition), giving them a more vocal presence than their less pedantic and more forgiving peers. Plus, almost everyone is pedantic once in a while, depending on their mood that day.

By dropping just one word from the first of my two most infamous claims, I arrive at the slightly less incorrect opinion: "Pedantry: it's just how things work in the world." In the written, online world, anyway. Useful to know!

In an effort to partly forestall a flood of amusing corrections from pedants on the sharp lookout (a.k.a. "skimming") for errors here that they can denounce, I'll make the following statements of True Fact:

- I am a poorly-educated yokel, and I'm not an expert at anything.
- I speak only for myself.
- My opinions change daily, and I articulate them poorly.
- Everything I write is a baldfaced lie, except for the stuff you agree with.
- You're right.

Feel free to quote me directly on any of those statements, by the way.

The other big thing I learned, related to my second infamous claim, is that people evidently *really* detest tax collectors, more so than I'd ever have guessed. Politicians, take note.

OK then! No more opinions from me, ever again. And I hereby revoke all previous opinions that I've ever stated or held at any time, however briefly. And as a nice catch-all algorithm, let's agree that if I ever again accidentally voice something resembling an opinion or a possible factual error, whether you agree with it or not, then we'll just assume I'm wrong and you're right.

I suppose I should say something about Ruby, in keeping with the theme of this blog:

I like Ruby, but I miss list comprehensions from Python.1

However, some quick searches seem to indicate that someone somewhere has implemented them for Ruby, somehow. I guess I'll go take a look!

<forever>
</opinion>
</forever>


[1] attention, pedants: I also miss them from Haskell.

I will try not to turn this entry into a rant, because we've seen plenty of that as of late.

However, I would like to share my experience regarding Ruby and the communities I've encountered in order to represent a sort of difference between the enthusiast and the hyper-enthusiast.

I will not make comparisons to other languages, because frankly, they aren't relevant. I will however mention that I first played with Python 6 years ago and after about a year of tinkering went straight to Perl and stayed there until a little less than two years ago.

Upon finding Ruby, I was amazed by the language, but even more so by the community. A year and half ago or so when I started playing with it, I had never heard of DHH or 37 Signals or Rails or anything like that. I was enticed by my friend James Edward Gray II to learn the language, and soon thereafter began lurking about RubyTalk.

Soon I saw some names coming up a lot, both in conversations and in posts by the individuals themselves, such as David A. Black, Hal Fulton, Curt Hibbs, Chad Fowler, Jim Weirich, James Britt, and of course _why. This is just a random list of people who I noticed quite rapidly, but basically, these were people who came to Ruby before the Rails explosion, and they all have made significant contributions to the Ruby community.

There are hundreds of people I've spoken to in this community who have made some wonderful contributions to Ruby. Many of them are regulars on RubyTalk, some I've met at Ruby Users Groups (Such as new_haven.rb or NYC.rb), some I met at the RubyConf this past fall. These folks are what forms the core of the Ruby community.

In the last 3 to 6 months, there has been an incredible amount of buzz regarding Rails. It seems now, that the number of people who are interested in Rails moreso than Ruby, or those who are interested in Ruby because of Rails outnumbers the smaller core of those who just love Ruby. That doesn't bother me one bit.

Part of growth is accepting the changing face of a community. As our userbase changes, the needs, interests, opinions and desires are sure to change as well. The only issue is that of identity, of reputation. I do not want to be lumped in with the hyper-enthusiast, if the meaning of the word is faith based decisions.

I also don't want everyone who knows I'm into ruby to assume I've mastered Rails and that I love it as much as they do. I haven't and I don't. Rails is very nice, and I'm at the beginning of a rather large scale project in it, but to me, it's just another impressive piece of Ruby software. No amount of marketing or hyper-enthusiasm is going to change my opinion on this. Maybe when I'm done with my project, I'll have some substantial experience based opinion on it, but as for now, I'll leave the defining word on Rails to those who know it and use it best.

The core issue here is that the level of noise is rising and rising in the communities. Or at least, some of us percieve it as noise. Do we really need to sell ruby? Do we really need to focus on standardization and point for point comparisions between language Foo and Bar? In my experience, Ruby sells itself. If you want to impress a potential employer, show them some software written in it, show them some things you've done. Prototype something quickly and cleanly and let them see it up front.

All this time that some very vocal members of the community spend 'defending' ruby or preaching it's wonders from the mountaintops, myself and many others spend doing ruby. To me, that's worth a lot more. To others, maybe it's not. I have no problem with this difference in opinion. I just need to make it clear that I came to Ruby before it was cool, and even if people were calling me a tax collector, or even comparing me to a COBOL programmer, I'd still love it.

If you want to support Ruby, let it speak for itself in beautiful code. That is far louder (and far more useful) than faith based words. So this might have turned into a bit of a rant after all, but I just needed to speak up a bit for the Old School Rubyist, who doesn't give a damn about what loud people on either side of the fence are saying.

Lots of people have been discussing symbols in Ruby, and seem have converged on the explanation that symbols should be used whenever you're referring to a name (i.e. an identifier or keyword, essentially), even if you're talking about a hypothetical name that doesn't really exist in actual code yet.

I think this is the correct idiomatic usage, and it's a pretty good way to explain symbols. But I also think it's going to feel a bit hollow or contrived to someone coming to Ruby from a background in (say) JavaScript, Python, or even Java. If I were them, I'd be thinking: "Um, OK. Intent, intent, intent. Got it. But... isn't a program-source identifier a fairly abstract notion to reify as a first-class object type, especially going so far as to give it a special syntax? And did I just use the word 'reify'? Geez."

I mean, Ruby symbols are right up there with numbers, strings, regexps and the like as first-class lexical entities. I'm guessing that this feels like a really odd decision to a lot of programmers. They might be comfortable with the "intent" explanation (which, incidentally, is similar to why I tell people I like tuples in Python so much -- they help me express tuple-ish intent better than a list). Comfortable, sure, but they're probably not wholly satisfied. It still smells a little fishy.

Am I right?

I'd like to offer my own humble take on Ruby symbols, in the hope that it'll clear things up a teeny bit more. Nothing I'm going to say in any way negates what folks have concluded already, which is that symbols are best viewed as representing names in program code, not as "lightweight strings".

Metaprogramming crash-course

Symbols as first-class objects are an idea that's usually associated with Lisp. I don't want to force you to learn any Lisp, and I won't show you any Lisp today. But hopefully I can give you the flavor of how symbols are used in Lisp by describing a "hole" in Ruby that I hope will be fixed someday.

As a toy example, let's take a look at the following Ruby code, which dynamically creates four methods and attaches them to an empty holder class, using eval.

#!/usr/bin/env ruby
# define a blank class as a holder for some methods
class BigMeanGiant
end

# Now add some silly-ish methods, using a flavor of eval.
# They're going to be instance methods, because it's as if
# we defined them inline inside the class definition above.
# When invoked, the giant yells the name of the method.

%w(fee fi fo fum).each do |name|
  BigMeanGiant.class_eval <<-EOS
    def #{name}() 
      puts 'Giant says:  #{name.upcase}!'
    end
  EOS
end

# invoke the methods, just for fun
begin
  g = BigMeanGiant.new
  g.fee
  g.fi
  g.fo
  g.fum
end

When you run this little program, it obligingly prints:

Giant says:  FEE!
Giant says:  FI!
Giant says:  FO!
Giant says:  FUM!

This program is roughly the "hello, world" of metaprogramming in Ruby. We've written some code that generates code on the fly: in our case, four nearly identical methods on BigMeanGiant called 'fee', 'fi', 'fo', and 'fum'. It's almost the same as if we'd written the code like this instead:

#!/usr/bin/env ruby

class BigMeanGiant
  def fee() puts "Giant says FEE!" end
  def fi()  puts "Giant says FI!"  end
  def fo()  puts "Giant says FO!"  end
  def fum() puts "Giant says FUM!" end
end

# invoke the methods, just for fun
begin
  g = BigMeanGiant.new
  g.fee
  g.fi
  g.fo
  g.fum
end

Running this version of the program has the same output.

What did we do that for?

Although this isn't meant to be a lesson in metaprogramming, let's make sure we're all on the same page here. The second version is clearer, right? Why would you ever do the first version?

You almost certainly wouldn't do it in an example this small, but the DRY principle tells us to avoid duplicating code. You can only get so far with function abstraction. Without metaprogramming, you can't really compress the BigMeanGiant class much. You might factor out some of the repetition with a helper function:

class BigMeanGiant
  def say(msg) puts "Giant says #{msg}!" end
  def fee() say "FEE" end
  def fi()  say "FI" end
  def fo()  say "FO" end
  def fum() say "FUM" end
end

But it's not much of a savings, because you still have to write all the stubs. Imagine you're writing an HTMLOutputter class, with one method for every HTML tag -- you'll have to write a few dozen stubs, which is more than just annoying. It's also probably more error-prone, since you'll have so much code it'll be harder to spot missed tags, duplicated tags, incorrect method bodies, and so on. And if you have to go back and change them all in some minor way, your refactoring editor may or may not be able to help, depending on what change you have in mind.

In short, having lots of similar-looking code is a Bad Thing.

To solve problems like this in Java, you either have to build elaborate and inevitably awkward dispatching infrastructure, or you have to use external code generators, then hack your build system to know how to generate and then use the generated code.

This, incidentally, is why you so often see generated code in large Java projects -- it's because Java offers no language-level ways to deal with problems like this. And of course, this is only one type of problem that's solved elegantly with metaprogramming; there are many other classes of problem that are equally difficult to implement cleanly in Java.

OK, we're all on the same page now, right? Generating code on the fly can lead to cleaner, more maintainable code, assuming you use taste and good judgement and blah blah blah. You get the idea.

The example explained

Continuing with my quest to get us all on the same page, let me make sure you understand the code in the first example. The relevant part is this blob right here:

%w(fee fi fo fum).each do |name|
  BigMeanGiant.class_eval <<-EOS
    def #{name}() 
      puts 'Giant says:  #{name.upcase}!'
    end
  EOS
end

This weird-looking snippet, interpreted in English, is saying:

  1. Make me a list of the strings "fee", "fi", "fo", and "fum".
  2. For each one of those strings:
    • substitute it into another string below, containing a Ruby method definition
      • The first time, use it as the method name.
      • The second time, use it (uppercased) as what the Giant says.
  3. Then call class_eval to turn it into a real method on the BigMeanGiant class.

Make sense? We're constructing method definitions in a loop, as strings, then passing them to the Ruby interpreter to attach them to a class. It's not all that different from putting the code in a Ruby source file, then invoking the interpreter; it's just that we're controlling the process ourselves at runtime.

The argument to class_eval is a string. The string contains code. Before class_eval gets hold of it, it's Pinocchio, wanting to be a Real Boy. class_eval is the fairy that sends him off to Pleasure Island to be ridiculed and learn valuable lessons, or whatever the interpreter does in its Big Black Box.

So far, so good. eval seems like a useful thing to have in your language, if you use it with caution.

Trouble in Paradise

So let's say there's a bug in my generated methods. Maybe the giant isn't saying anything, or he's saying the wrong thing. Let's say I'm having trouble figuring out the bug by staring at my code-string, which is really just a template. It's not real code until the interpreter finishes evaluating it and attaching it to the BigMeanGiant class.

So I fire up the debugger, and step through the code, and immediately notice a few things:

  1. The call to class_eval is atomic. The debugger just steps right over it.
  2. Calls to the generated methods are also atomic.
  3. I have no way of printing out the generated code.

In other words, your metaprogramming-generated code isn't "first class" in the same way your normal source code is. It's not visible to the debugger, and it's not available to other tools either. (For instance, rdoc lets you include the source code in the generated documentation, but I don't think there's any easy way to have it know about your eval-generated code.)

There are some games you can play that might make some of these things achievable. For instance, you might be able to override class_eval to store the original source code (after the template substitution) in the class somewhere, and then provide an API for getting at it for your favorite debugger. But to the best of my knowledge, it's not something that's supported "out of the box" in Ruby, and it means that working with generated code is harder than it really needs to be.

Even if I'm completely mistaken here, and someone comments with a way to print out a generated method's source code (which would be pretty nifty), the whole experience still falls remarkably short of the metaprogramming facilities in Lisp.

To clarify, let's peer more closely into the lifecycle of that generated code. There are some distinct activities that rush right by us in Ruby, things we might actually want some control over.

We really will make our way to symbols soon, promise.

Constructing the code string

We start with a string, which the first example has in a "here doc" -- one of Ruby's genuine Perl-isms that you're free to view with suspicion. Python's syntax would be a triple-quoted string, which I think is nicer, but what's done is done. Here's the string again:

    def #{name}() 
      puts 'Giant says:  #{name.upcase}!'
    end

It could just as easily have been a normal, double-quoted string, even a one-liner:

  "def #{name}() puts 'Giant says: #{name.upcase}!' end"

However, because dynamically-generated code is notoriously tricky to debug, most of the time you'll want to format code in template strings as clearly as possible.

I'm calling it a template because Ruby strings can contain inline expressions, delimited with #{}. In Java you'd use string concatenation, e.g.:

"Giant says: " + getThingGiantSays() + "!"

Python has the printf-like % operator, and other languages have their own approaches. The Ruby way is probably more readable if the substituted expressions are short; using something like sprintf (which Ruby also has) will be better if there are long expressions. Basically you want to do whatever makes the code template look as much as possible like the code it's going to turn into.

Here's Secret Observation #1: in Lisp, your code template isn't a string. It's a data structure that represents the tokenized and partially-parsed code. If Ruby had this feature, the BigMeanGiant example might look something like this:

%w(fee fi fo fum).each do |name|
  BigMeanGiant.class_eval START_CODE_TEMPLATE
    def #{name}() 
      puts 'Giant says:  #{name.upcase}!'
    end
  END_CODE_TEMPLATE
end

I put those big START/END tokens there in an attempt to make it clear that what's inside them is NOT a real boy; it's Pinocchio, and it will take some major Good Fairy work to make it real code.

But notice that the code inside the template is actually syntax-highlighted properly. When it was all inside a string (heredoc, double-quoted, or otherwise -- it's still just a string), it was all highlighted in light blue, which is what my editor tells me Strings should look like. My editor was nice enough to highlight the substitution expressions in brown, but you still need to realize they're substituted before the final string is used as an argument to class_eval. But inside the CODE_TEMPLATE, we know it's going to be code, so we can invoke the syntax-highlighter on it. Helps you see what's going on more clearly. And auto-indenting, tagging, and other IDE functions will work on it. Muuuuuch nicer than code in a string, wouldn't you agree?

Imagine that you could pass around one of those CODE_TEMPLATE doohickeys as an object, one that actually represented the Pinocchio-code in a way that let you traverse it and modify it before passing it off to eval. That seems like it could come in quite handy, and in fact it does. For one thing, it makes it far easier to do meta-metaprogramming, where you're writing code that generates those code templates. But at a perhaps more mundane level, it makes it possible to create new syntactic constructs in the Ruby language.

At this point, some people will cringe and shudder and proclaim: "Evil! What you just said is Pure Evil!" Lots of programmers, maybe even most of them, are so irrationally afraid of new syntax that they'd rather leaf through hundreds of pages of similar-looking object-oriented calls than accept one new syntactic construct. I blogged about this once, in an article called Language Trickery and EJB. That article actually managed to convince a bunch of hardcore Java programmers that new syntax might actually be a useful tool. Maybe it'll convince you too. If not, well, feel free to skip to the next section.

It would actually take me too far afield to go through a detailed example of how adding a new syntactic control-flow construct to Ruby could turn into a huge benefit for your project. Imagine, though, that Ruby didn't have here-docs, and that you were practically drooling with jealousy over Python's triple-quoted strings. If you're a Java programmer, and you're not drooling purely out of habit, then you should definitely drool over multi-line strings. It boggles the mind that they didn't include it as a language feature, and in Java we wind up doing zillions of manual concatenations to produce long strings (which usually by then look nothing like the thing they're trying to represent.) Ah, me.

If Ruby didn't have here-docs, but Ruby had those CODE_TEMPLATE thingies and one system hook that allowed you to control the evaluation of those templates, then you could implement here-docs pretty easily. Because the code-to-be is represented as a data structure, allowing you to quickly and easily filter out the #{}-substitution elements, you could simply evaluate whatever's inside those elements, and not evaluate anything else in the template. That's all they really do. And of course (much) more sophisticated syntactic constructs are also possible, if you put in more work.

That's the kind of thing Lisp programmers do for breakfast before going and writing their application code. And the funny thing is, it could really be super easy in Ruby -- maybe even easier than in Lisp. It's just that Ruby doesn't support it today.

If the hairs are all standing up on the back of your neck, and you're just recovering from shock and trying to think of the dirtiest word you could possibly call me, well, take a few deep breaths, nice and slow. It just means I'm a dog person and you're a cat person, or something like that. Let's not bite each other. Many people (notably Paul Graham in "On Lisp") have spent lots of effort explaining how this kind of programming has to be treated with MUCH more deference and caution than ordinary API programming. Language extensions and minilanguages can be extremely powerful and useful -- imagine where we'd be without regular expressions, for instance -- but they also require tons more care, documentation, and thought than defining an ordinary function.

You're already sort of doing this kind of "language extension" programming every time you call eval -- for that matter, you're doing it whenever you invoke a separate code generator, or open up a class and add stuff to it, or use a tool like yacc or ANTLR. We're completely surrounded by languages, large and small, all the way down to the minilanguage you use for ordering coffee at Starbucks. It'd be hard to get along without them.

Evaluation

Once you have that code template as an actual object, as opposed to a string that you need to parse yourself, then you could do all sorts of things with it. For one thing, you could pretty-print it. It's effectively in parse-tree format, so all you'd need to do is decide the rules for line breaks and spacing between various token types. For another thing, you could tell your debugger about it, which would allow you to inspect and step through generated code. And evaluation -- the creation of actual code from your template -- would no longer be the black box that it is in Ruby today (and in Python, Perl and JavaScript, for that matter.) More control means more opportunities to remove DRY violations, and do so in a way that has strong(er) long-term maintainability characteristics. I mean, you have to admit, not being able to inspect or step through your generated code makes maintenance a bit of a tricky proposition.

(Note: see the important correction Jim Weirich made in the comments section. --steve)

Symbols at last

Those nonexistent code templates I've been referring to -- that is, objects (collections, really) that represent snippets of code to be evaluated -- they're really just syntax trees representing your source code. They're similar to the output you'd get from any parser, including generated parsers from tools like ANTLR. Or maybe a more familiar example is the XML DOM -- an object-tree representation of the parsed XML file. You have to admit, working with a DOM is a lot more convenient than working with a string containing raw XML. It's a huge difference, and it's a feature Lisp has that Ruby mostly lacks, at least today. A set of features, really: it's a rich programming domain.

In a system with first-class syntax trees represented as language entities, in a way that allows you to interact with the lexer, parser, and evaluator (i.e. different components of the Ruby interpreter), symbols make a whole lot more sense. A symbol is literally an object that represents a name in the code tree. If you had a code template snippet representing this code:

  def fum() say "FUM" end

Then your syntax tree would contain a Symbol object for each token in the code except for the string "FUM" (which would be a String), because that's just a string and not a source identifier or keyword, and also except for the parens in the arg list, but that's another long story that we don't have time for today.

So Ruby's symbols are really a placeholder for grand things to come. Ruby is already a very powerful, capable language, but it has some weaknesses in its ability to process Ruby code at runtime. Your only real tool today is eval (which comes in several flavors in Ruby, but that's irrelevant to our discussion), and it's a big black box. Once your code template is handed over to the Good Fairy, crossing that magical line between your program and the Ruby interpreter, you've lost it, and what you get back is effectively an opaque binary blob wrapped in a thin Method (or UnboundMethod, etc.) class that doesn't remember much about its original symbolic representation.

Well, that went on way too long. Was it helpful?

I recently started writing an article about Domain Specific Languages (DSL's) and Ruby. While conceptually I think I understand what a DSL is, I think a specific definition is elusive. After scrutinizing several articles and the Wikipedia, I can propose a limited definition of a DSL as a custom language designed to solve a specific problem.

Some examples of DSL's listed are unix mini (or little) languages, such as sed, awk, troff, m4 or make. The list is quite long, and actually, could go on forever, since most any language, computer based or not, could be considered a DSL. But for now, I'll limit this entry to languages used in the computer domain.

From my work, I see DSLs used for two main purposes. One, is as a friendly way to provide data (configuration or otherwise) to a program. The other is a friendly way to let users write business rules for a particular task. This is usually motivated by the desire to let the end user write code without realizing they are actually coding.

Except for very simple command lists, you see this second type less often because the complexity usually requires one to either build a real mini language or, if using a traditional general purpose language (GPL), the derived DSL is usually more cryptic or complex than just using the GPL itself.

When designing a DSL, the programmer has to weigh the options of taking the effort to build a full featured language (using the likes of YACC or Bison) or to make a simpler language that can usually be parsed with a hand built parser. It's the choice between 'simple and now' or 'full featured and later'.

But the danger is that 'simple and now' languages, if successful, tend to grow into ugly and complex later.

Consider make. I'm not intimately familar with the origin of this language, but here is my wild guess as to how it came about:

Programmer: Hmm, I'm tired of repeating these build steps over and over. I need to make a control file to do this for me. I also want to be able to take this with me to other platforms, so I'll need to use a portable language. Hmm, I know C, I'll use it.

Now lets see, I don't want to go to the effort of writing a real language, I just need some simple features, so I'll write my own parser.

I need a simple way to defined dependencies and a target, something like:


target : dependencies

Yeah, the ':' is good. You don't see colons used much in filenames.
Now I need to define a list of actions. Hmm, how about:

target : dependencies
begin_actions
action1
action2
...
end_actions

Wow, this is hard. These blocks are killing me. Hey, wait a minute, I can get rid of these blocks if I just make the user use a tab as the first character on an action line, kind of like Fortran, but more sinister since you can't see the tab character (woohaahaaha). This way I can do a simple character test in C and don't have to do any complex parsing. The user shouldn't mind too much.

Having a critical syntax that depends upon an invisible character is just a horrible design -- for the end user. For the programmer, it was pragmatic and reasonable.

Instead of writing a homegrown parser, another alternative is to create a grammar and use a tool like YACC and create a parser. This definitely falls on the complex side of the scale. For someone who doesn't do this everyday, even simple tasks take a huge amount of brain power and one ends up focusing more on minutia of the DSL, and not on higher level usability issues.

Several years ago I needed to write a description file of geometrical stack. Several vendors had their own format, which were mostly line based, but a couple supported scoping inside a block. None, however, supported variables or constants. Their files were basically glorified configuration files.

I started to write my own using Racc. It was a great learning experience for me. We chose to write our own parser because we wanted to limit what could be done in the file (why, I don't know). I spent about three weeks on the project and things were progessing nicely. It almost looked like Ruby. But, it was tedious, and other things got prioritized over the project before I could finish.

Later I revisited the project. This time I thought, hey, why should I write my own parser, XML/XSLT and xmlproc will do this for me. So, within a couple of days, I had done what took me three weeks previously. I thought it looked readable and the time and was able to partially convince a colleage that it was readable. About a week later, when I came back and revisited the file, I realized, XML is not readable. Sure, if your brain is in XML mode, then it can filter out the syntax noise. But when one is concentrating on getting a particular job accomplished and thier brain is forced to task switch between their problem domain and mentally parsing XML, overloaded synapses are a certainty.

The third time around, after the Ruby DSL hype had been going around for a while, I decided to use Ruby. This time, I was able to create the DSL in about five minutes. It was readable, and I was able to focus on the end users frame of reference.

The moral of this story is, don't write a mini language if you don't have too. And, don't settle for a simple DSL when a full featured one is needed. Consider extending a GPL into a DSL. Particularly an expressive language that is good at creating a readable DSL -- like Ruby.

Back to the original question of a what exactly is a DSL. One can either write a DSL from scratch or use a GPL with a few added functions to create a DSL. But if any GPL can be made into a DSL, doesn't that make all languages DSLs?

Both Jim Weirich and Yohanes Santoso posted about Ruby’s Symbol class today. As Yohanes noted, there’s not many weeks that go by where there’s no question about Symbols. I thought I’d throw in my two cents, expanding on a mailing list response ([ruby-talk:172842]). First, let’s look at what ri has to say about Symbol objects:

Symbol objects represent names and some strings inside the Ruby interpreter. They are generated using the :name and :"string" literals syntax, and by the various to_sym methods. The same Symbol object will be created for a given name or string for the duration of a program’s execution, regardless of the context or meaning of that name. Thus if Fred is a constant in one context, a method in another, and a class in a third, the Symbol :Fred will be the same object in all three contexts.

The beginning of the confusion about Symbols being like Strings is straight from the source in this case. As both Yohanes and Jim point out, though, Symbols shouldn’t be used as "Strings-lite". At a minimum, to be useful that way, you’d have to convert each Symbol into a String (#to_s) before you could operate on it. If you shouldn’t use Symbols as if they were immutable strings, what good are they? Yohanes covers the theory well: helping to express intent. Jim covers the practical reasons well:

  1. Naming keyword options in a method argument list.
  2. Naming enumerated values (e.g. like enums in C).
  3. Naming options in an option hash table.

As Jim says, “Symbols are about naming and identifying things.” I don’t quite agree with his definition (“A Symbol is an object with a name”), preferring to say that a Symbol is an object that is a name. It’s a very subtle difference, mind you, but an important one in that there is no meaningful distinction between a Symbol and the name that it represents. That said, we’re still left with the question asked by Steve Litt, “One thing—why not some_call(:@my_variable)?”

This is where Yohanes’s discussion on intent matters. You aren’t naming your variable when you call attr_accessor. You’re naming your method. The magic here isn’t in the Symbol; it’s in attr_accessor.

>> class Foo
>>   attr_accessor :bar
>> end
=> nil
>> baz = Foo.new
=> #<Foo:0x2d8aea8>

Thus far, baz has no instance variables. But it does have two instance methods:

>> baz.methods - Object.methods
=> ["bar", "bar="]

If I call the reader method (Foo#bar), I still don’t get an instance variable:

>> baz.bar
=> nil
>> baz
=> #<Foo:0x2d8aea8>

It’s only when I call the setter method (Foo#bar=) that my instance variable is created:

>> baz.bar = 32
=> 32
>> baz
=> #<Foo:0x2d8aea8 @bar=32>

The intent of the Symbol is that it’s just a name. The intent of attr_accessor is that it creates two methods for each name that it’s been given. It is almost coincidental that these methods work on a variable of the same name. It doesn’t have to be the same, as I demonstrate below.

require 'digest/md5'
class Module
  def md5_accessor(*names)
    names.each do |name|
      var = Digest::MD5.hexdigest(rand(65536).to_s)
      define_method(name) { || instance_variable_get("@_#{var}") }
      define_method("#{name}=") { |v| instance_variable_set("@_#{var}", v) }
    end
    nil
  end
end

class Foo
  md5_accessor :bar, :baz
end

moo = Foo.new
moo.bar = 5
moo.baz = 7
moo
puts moo.bar, moo.baz

I've always liked the fact that nil evaluates to false. This is handy in conditional expressions and makes ||= possible.

However, something I didn't expect is a bit annoying:
nil.to_i gives you a 0, which evaluates to true in ruby.

So stuff like this happens:

irb(main):002:0> puts "hello" if nil.to_i
hello
=> nil

At a first glance, it seems like zero might have been better replaced by nil or an exception.

Does anyone have any insight as to why nil.to_i returns zero and why that might be more useful or better than an alternative solution?

As has become tradition, Christmas brings us a new version of Ruby. Thanks to Santa Matz, Ruby 1.8.4 is now available.
ChangeLogs can be found here.
A big thanks to Matz and all those working hard to make each new release better than the last.

Two great newbie resources made my attention-width this morning:

1) Learn to Program (using Ruby), by Chris Pine. There are tons of books out there that assume you know how to program already and so the title and subject end up being Learn to Program XXXX, but what about Newbies? Chris steps in and decided to use Ruby as the base. His book is due soon as well, which he assures me is even funnier.

2) Rails Weenie. Hey, that's me! "Sign up and you start off with five points. Offer up points for your questions. The harder the question, the more points you wager."

No doubt Rails is becoming popular - just looking at the number of folks joining the ruby-talk mailing list and asking Rails specific questions. It's happening very frequently now - I think mainly because of the confusion between what is Ruby and what is Ruby on Rails. For the most part, they are kindly directed over to the Rails mailing list for better help with their questions. However, the frequency of this question and reply session is picking up dramatically. Thus, it seems like the most natural solution is to rename either Ruby or Ruby on Rails to something that helps differentiate between the two.

I'm just kidding about renaming the projects. But the comment board is open - hit us up with some of your (humorous) thoughts.

Tonight, the Utah Ruby Users Group had its monthly meeting. We've been hovering aroung 20 attendees for several months now, with a traditional presentation format. This month seemed like a good time to do something different, so we decided to try a more hands-on meeting.

Jamis Buck (of Net::SSH, Needle, and Rails fame) put together several 'topics' that we could pair up and hack on. The idea was to let people pair up and work on things that were interesting and skill level appropriate, and at the end of the night compare notes on how pair programming and strict test first programming worked for people.

I don't know if it was the meeting plan, or the proximity to the holidays, but things didn't work out like we'd hoped. Only about 6 people showed up, and the hacking topics didn't really appeal to us. One of the attendees had a question about getting AJAX working in a little Rails app he'd been working on though, so Jamis led an impromptu 90 minute session on using AJAX in Rails. (I guess that's what being agile is all about.)

For January, we're going back to our old format. I understand the presentation will be about Ruby/Cocoa. Whatever it is, I plan on being there. With this group, missing a meeting means you're really missing out.

Are you involved in your local Ruby Brigade? If not, do you know what you're missing?

A few nights ago I had the good fortune of leading the first Phoenix Ruby Users Group meeting in many months, and the difference between this one and the previous meeting were amazing. Expecting to see maybe eight or ten people, a fairly sizable training room (graciously provided by Cyclone Commerce) was completely filled. By rough estimate there were 25 to 30 people. Were in the world did they come from?

A bit of history: I came to Ruby sometime in 2000 or 2001. It was probably Dave Thomas’ article in Dr. Dobbs that piqued my interest. I remember browsing through a copy of the first edition of Programming Ruby at a local Barnes & Noble, and being put off by some of the syntax, but, for reasons now unknown, I gave Ruby another shot. Part of learning Ruby was getting active in the Ruby community, which meant lurking, then participating, on the ruby-talk mailing list, and learning about the main Ruby Web sites, such as Ruby Central and Ruby Garden.

Some time early on, interested in meeting other Rubyists, I added my name to the Ruby Garden wiki page for the Phoenix Ruby Users Group. There were, I think, two names already there. I may have tried sending E-mail to these people, but nothing ever came about. It wasn’t until early 2005 that, hearing that people were doing well using (then free) Meetup.com to organize user groups that I did actually attend my first Phoenix meeting. On the up side, I met great people (in fact, it led to my joining them in the Web design and development company, 30 Second Rule ). However, over the course of three or four meetings, it was always the same three people, and the user group, as such, just dissolved. Though the Rails Summer of Hype meant Ruby was getting routine attention on various Web sites (such as Slashdot, and here on O’Reilly), it seemed as though Phoenix was just never going to be a hotbed of Ruby activity.

Getting Refreshed

However, a few months ago, a few folks from some local companies began to realize that indeed there were a number of interesting people and companies here in the Valley of the Sun , but for the most part they were operating in complete ignorance of one other. Copping a tune from Refresh Dallas, Refresh Phoenix was born, with the goal of bringing together Web developers and designers in a relaxed social environment so we could meet, get acquainted, learn new things, and share ideas and experiences.

The first meeting in November went great. Our fears of pitiful turnout were completely unfounded; there were probably 25 to 30 people there. It turned out that many people were thinking the same thing, and were eager to get out of their cubicles and actually talk with people, face-to-face.

The big surprise for me, though, came as we asked everyone gathered to say a bit about themselves, what they do, and what things were they interesting in. Probably half a dozen people mentioned Ruby or Ruby and Rails, saying either they were just getting started or looking learn.

At the second Refresh Phoenix meeting I announced that I was looking to revive the Phoenix Ruby group; before I left I collected a dozen names. Shortly afterward I made plans for our first meeting, expecting perhaps eight or ten of those on my list to show up, as well as a few folks from Cyclone Commerce. I was mistaken.

The meeting was scheduled to begin at 6:00 PM, and by 6:15 PM nearly every seat in the good-sized training room was taken. Wow.

Since this was largely a Get Acquainted and Figure Stuff Out meeting, I asked if each person could say who they were, how much Ruby they knew, and what they hoped to get from the group. The responses were somewhat surprising. Most people had taken a stab at Ruby coding, but were just getting started. That made some intuitive sense. I was really expecting to hear a room full of people telling me they all wanted to learn Rails. But, while that did get some mention, most people expressed a primary interest in learning Ruby itself, in expanding their general programming skill set. Some wanted to get away from Java, some wanted a better understanding of meta-programing with a dynamic language. But the interest was in Ruby itself, not some particular framework or application.

Since so many were new to Ruby, I offered up some resources. By a show of hands, though, most of the room seemed unfamiliar with the ruby-talk mailing list (home to the world’s friendliest developer community) and most of what I consider the better known Ruby Web sites. So here was a room full of people, many of whom were already somewhat familiar with Ruby, many of whom had taken steps to learn Ruby, yet were not even lurking on ruby-talk or surfing the Ruby Garden wiki. (Thankfully, at least some folks already knew about ruby-doc.org.)

The meeting went great, and I’m looking forward to the next one, in January. It’s really nice to be around so many people so interested in expanding their horizons.

The Takeaway

I think one tends to get the impression that the discussions on ruby-talk, or on Slashdot or O’Reilly, or on the many Ruby blogs, somehow represent the “Ruby community”, but the reality is that there are good numbers of people actively interested in Ruby, but unaware or indifferent to certain public forums and currents. This suggests that while activity on the main outlets correctly indicate a growing interesting in Ruby, the real numbers are much larger than may be readily apparent. And the comments from people I spoke with suggest that while certain topics and tool sets get a fair amount of public buzz, there is tremendous interest in all the myriad aspects of Ruby.

If you are a publisher, you may want to rethink jumping on whatever is the current bandwagon for your next Ruby book. People want to know all about all of Ruby. And if you are part of a company looking for developers, thinking that Ruby may give you an edge, but concerned about finding people, know this: There are far more Rubyists than you know.

In my previous entry I had some takers on trying to write a nice, compact, method that handled round a float down to a certain decimal place.

For fun, I decided to benchmark each implementation, along with a small C implementation I wrote. Here's the lineup:

require 'benchmark'
require 'prec_c'
include Benchmark

class Float
  def prec_caleb1(x)
    sprintf("%.0" + x.to_i.to_s + "f", self).to_f
  end

  def prec_caleb2(x)
    (("%.0" + x.to_i.to_s + "f") % self).to_f
  end

  def prec_james(x)
    ("%.0#{x.to_i}f" % self).to_f
  end

  def prec_jonas(x)
    (self * 10**x).to_i / (10**x).to_f
  end

  def prec_fansipans(x)
    to_s[/.*\..{#{x}}/]
  end
end

n = 50000
bm do |x|
  r = rand(6)
  x.report { for i in 1..n; 5.44235102.prec_c(r); end; }
  x.report { for i in 1..n; 5.44235102.prec_caleb1(r); end; }
  x.report { for i in 1..n; 5.44235102.prec_caleb2(r); end; }
  x.report { for i in 1..n; 5.44235102.prec_james(r); end; }
  x.report { for i in 1..n; 5.44235102.prec_jonas(r); end; }
  x.report { for i in 1..n; 5.44235102.prec_fansipans(r); end; }
end

I ran the code a couple of times to make sure the results came up rough the same. They did. Here are the results (sorry for the formatting):


impl user system total real
caleb_c 0.330000 0.000000 0.330000 ( 0.325121)

caleb1 0.450000 0.000000 0.450000 ( 0.454775)

caleb2 0.460000 0.000000 0.460000 ( 0.456334)

james 0.410000 0.000000 0.410000 ( 0.405698)

jonas 0.480000 0.000000 0.480000 ( 0.486741)

fansipans 0.950000 0.000000 0.950000 ( 0.944716)

It looks like James is the winner, at least in terms of efficiency (as long as you don't count my C extension, which kind of breaks the Ruby spirit).

Here's that code, in case you're interested:

#include "ruby.h"
#include <signal.h>
#include <time.h>

static VALUE prec_c(VALUE klass, VALUE prec)
{
  VALUE str = rb_str_plus( rb_str_new2("%."), rb_funcall(prec, rb_intern("to_s"), 0) );
  VALUE str2 = rb_str_plus( str, rb_str_new2("f") );

  char s[20];

  sprintf(s, StringValuePtr(str2), NUM2DBL(klass) );
  return rb_funcall(rb_str_new2(s), rb_intern("to_f"), 0);
}

void Init_prec_c() {
  rb_define_method(rb_cFloat, "prec_c", prec_c, 1);
}

I'm sure someone can find some fallacies in my code that makes for unfairness in my benchmarking, but for the most part I think the data is fairly reliable.