January 2006 Archives

James Britt

AddThis Social Bookmark Button

The ruby-doc.org Web site has undergone a transformation. Accolades have been pouring in for the new look, for which all credit must go Dan Ritz, one of my cohorts at 30 Second Rule.

There are still some rough edges. Ruby-doc began life as a blog-based news site that hosted the core API pages and a handful of other docs and tutorials. Over time the number of pages and resources have grown. It no longer makes sense to try to track and announce every new Ruby resource; the Web is awash in them. Instead, the focus needs to shift to making available a robust set of documents and tutorials, and helping people find the information they need to make the most of Ruby.

The growth of the site was somewhat haphazard, making the upgrade more of problem than it really should have been. There may still be some broken or misdirected links, so please bear with me, but feel free to drop me a line (jbritt AT ruby-doc DOT org ) if you find something amiss.

To alleviate such problems in the future, I’ve changed the site to run under Ruby’s wonderful Nitro Web framework, which I encourage others to investigate. Nitro greatly eases the development and maintenance of dynamic Web sites.

And I want to repeat my thanks to those people taking the time and trouble to write Ruby documentation. You folks are life-savers.

AddThis Social Bookmark Button

As you are probably aware, the Ruby interpreter and some of the core libraries are written in C. Over the next few weeks I plan to share a look at some of the internals of Ruby and how it achieves some of the things it does from the C side of things.

The first point of interest is the VALUE - Ruby’s internal representation of its objects. In the general sense, a VALUE is just a C pointer to a Ruby object data type. We use VALUEs in the C code like we would use objects in the Ruby code.

some_function(VALUE arg_object)
{
  some_method(arg_object);
}

One would expect that the VALUE is just a typedef to a C pointer and there’s a lookup table as to which object it represents, and this would be partially correct. However, there’s also some trickery involved.

Instead of implementing the VALUE as a pointer, Ruby implements it as an unsigned long. It just so happens that sizeof(void *) == sizeof(long) - at least on the platforms I’m familiar with. After all, what is a pointer? It’s just an n-byte integer that represents a memory address.

But because of this, there’s some tricks Ruby can perform.

First, for performance purposes, Ruby doesn’t use the VALUE as a pointer in every instance. For Fixnums, Ruby stores the number value directly in the VALUE itself. That keeps us from having to keep a lookup table of every possible Fixnum in the system.

The trick lies in the fact that pointers are aligned in 4 byte chunks ( 8 bytes on 64 bit systems ). For example, if there was an object stored at 0×0000F000, then the next would be one stored at 0×0000F004. This jump from 00 to 04 in the lower nibble is important. Expanding out as bits, it is: 00000000 and 0000100. This means that if we use the VALUE as a pointer, the lowest two bits will always be 0s.

Ruby uses this to its advantage. It will tuck a 1 in the lowest bit, and then use the rest of the space (31 bits) to store a Fixnum. One of the bits will be used for the sign, so a Ruby Fixnum can be up to 30 bits in length.

irb(main):021:0> (2 ** 30).class
=> Bignum
irb(main):022:0> (2 ** 30 - 1).class
=> Fixnum
irb(main):024:0> (-(2 ** 30)).class
=> Fixnum
irb(main):025:0> (-(2 ** 30)-1).class
=> Bignum

Ruby uses the other bit to help distinguish other common types, like false, true, and nil. Symbols and their IDs are also stored with this bit on, so Ruby recognizes it as a special instance and interprets accordingly.

The rest of the time a VALUE is a good old fashioned memory address, which points to an object structure in memory.

ruby_value_diagram.png

So there you have it. I hope this little snippet was of some VALUE to you.

Steve Mallett

AddThis Social Bookmark Button

O’Reilly has begun a new book program called Rough Cuts that allows readers to follow along the development of a book in PDF form with updates along the way as the book evolves into a finished product.

One of the most in demand topics, as Tim’s post about Ruby book sales overtaking Python indicates, is Ruby. Suitably half of the new titles available concern Ruby. Ruby Cookbook , and Ruby on Rails: Up and Running.

I’m pleased to see this as I love the model and dove in head first when the Prag. Programmers released Agile Web Development with Ruby on Rails in the same style.

Tim explains, “In short, you can buy online-only access to the Rough Cuts directly from us for about 50% off the expected list price of the final book; you can pre-order the print book for about 35% off the list price; and you can buy both together for only about 10% more than the list price.” Why wait for the book to come off the press to dive into the material?

Gregory Brown

AddThis Social Bookmark Button

UPDATE: The bug mentioned below is probably harmless in your applications. My issue was actually with some dependencies who were fighting each other, and not with the bug mentioned below. However, if you are annoyed about gems returning false when you require them, feel free to read below how to fix it.

UPDATE2: The bug in one of Ruport’s example programs (Ruport itself never actually requires active_record), was that Transaction::Simple is included in a vendor dir of ActiveRecord and is required via gems in PDF::Writer, so they clash, dumping a few warnings. I’m not sure if this will have any side effects or not.

“If there were any more hurdles on this track, the thing would be made out of hurdles”

For those who have been following Ruport development, you know that I’ve gone through 4 computers in the last 5 weeks. That’s insane. But now, as I finally have had a chance to spend a few hours on a machine without it’s hardware breaking on me, I’ve run into software issues.

The current stable version of RubyGems (0.8.11) does not correctly load gems which use the auto_require feature.

So in the course of Ruport development, i found require 'lafcadio' and require 'redcloth' returning big fat falses on me! (Which was causing unsavory results elsewhere in the system)

Searching RubyTalk, Jim Weirich mentioned that it had been fixed in the CVS head.
Sure enough, it was.

I deleted all of the rubygems stuff from my ruby and site_ruby dirs, and then ran:

cvs -d :pserver:anonymous@rubyforge.org:/var/cvs/rubygems login
cvs -d :pserver:anonymous@rubyforge.org:/var/cvs/rubygems checkout rubygems
cd rubygems
sudo ruby setup.rb

I had to reinstall my gems, but once I did, I was back to getting trues instead of falses ;)

Now I have no clue how stable the CVS head is, so this is not a recommendation, but rather just a little experience I wanted to share :)

The good news is, I am back to coding… so those of you out there on the Ruport mailing list, be on the lookout for a beta preview of Ruport in the next day or two.

Thanks to the RubyGems team for quickly fixing this bug so that people who want to be on the bleeding edge rather than downgrading can do so :)

James Britt

AddThis Social Bookmark Button

I see that Agile Web Development with Rails , and the Rails 1.0 Web application framework, are finalists in the Software Development Jolt Product Excellence Awards.

Congratulations to Dave Thomas and all those busy Rails developers.

And my apologies for the corny title. Hard to resist.

Robby Russell

AddThis Social Bookmark Button

The list of speakers for Canada on Rails was announced a few days ago. This will be the first Rails-specific conference of its kind and will take place from April 13-14, 2006 in Vancouver B.C.

Here is a list of the scheduled speakers:

1. David Hansson, creator of Ruby on Rails
2. Thomas Fuchs, creator of script.aculo.us
3. Dave Astels, published author on Test Driven Development
4. David Black, creator of SCANF.rb, RCRArchive
5. Joe O’Brien, developer with ThoughtWorks
6. James Adam, creator of Rails-Engines
7. Steven Baker, creator of RSPEC
8. Michael Buffington, cofounder of Price.com, co-architect of MeasureMap.com
9. Robby Russell, founder of PLANET ARGON
10. Geoffrey Grosenbach, host of Ruby on Rails Podcast
11. Kyle Shank, lead developer of RadRails and Rubish
12. Jeremy Voorhis, lead architect at PLANET ARGON
13. Alex Bunardzic, founder of Jooto
14. Sebastian Kanthak, creator of FileColumn plugin
15. Amy Hoy, future author of a “Right-Brained Guide” to Ruby on Rails

Take a look at the schedule and register today!

Yes, I will be speaking there. :-) The title of my talk is, “Sneaking Rails Into The (Legacy) System.”

Hope to see you there!

AddThis Social Bookmark Button

The fine Ruby loving gentlemen at the Pragmatic Studio have just announced a Chicago based studio for February 16-18th.

This is just a note that I am planning on attending this studio and look forward to meeting others in the Ruby community. While I feel pretty proficient in Rails already (our intranet is heavily dependent on a few internal Rails applications), some of the newer things that have emerged in the last few releases have slipped past me and I haven’t been able to keep up. Plus, why not spend a few days away from work on the company’s dime, ya know?

I also will be available to sign virtual PDF based autographs on your favorite QtRuby PDF book. :)

AddThis Social Bookmark Button

Last week, I wrote about the Singleton pattern in Ruby much like Rusty Divine did about Java/C#/.NET at CodeSnipers. Since his second entry was about the Observer pattern, I thought I’d write about its Ruby implementation.

pat eyler

AddThis Social Bookmark Button

Red Letter: The Ruby Journal was announced on January 8th. (A pre announcement was made back in December that met with a variety of feedback.)

I’m pretty excited to see a Ruby specific monthly magazine, albeit distributed in PDF only. Knowing that there’s enough of a market to interest publishers in putting something like this together is an indication of the growth of the Ruby community.

I’ll be interested to see how the first several months go, assuming the magazine hits a good number of readers and pulls in enough advertisers, I think it will help push Ruby even further into the light. What does it mean if Red Letter doesn’t hit those marks though? (And, what constitutes a good body number of readers, or enough advertisers?)

I guess we’ll start getting answers in April and go from there, but it’s a lot more fun to make predictions. I think it’s got a pretty good chance of succeeding. What do you think?

James Britt

AddThis Social Bookmark Button

Over on the consistently good Lambda the Ultimate is a discussion prompted by Tim Bray’s posting, Don’t Invent XML Languages.
Somewhere in the LtU thread is a comment from Kay Schluehr::

A family of operators is not a language, not even a dialect. It is at most a jargon ( or gibberish ;)

Ruby is very good for creating DSLs (domain-specific languages), and this comment made me wonder:

  • When does something become a DSL?
  • What do domain-specific dialects and domain-specific jargon look like?
  • When would you opt to design a DSD or DSJ?

AddThis Social Bookmark Button

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?

AddThis Social Bookmark Button

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 briefly, 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. 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 hallways echoed with roars 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.

AddThis Social Bookmark Button

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.

Steve Mallett

AddThis Social Bookmark Button

Related link: Digg is Slashdot’s Death Knell

Frankly good riddance. Don’t get me wrong I was a faithful slashdot user, but digg has everything right that slashdot has had wrong.

Hidden submissions. While everyone agrees that a filter to the front page is a good idea it does leave the question of whether the stories are legitimately refused. I’m sure most are legit, but…

User moderated stories. Slashdot has a ‘flavor’. The editor’s. That’s cool. It is their site after all, but people obviously prefer their own flavor. If you don’t like digg’s flavor who’s to blame?

The biggest boon of the open backend is that you don’t have to wait to see that big story to approved by moderation if you don’t want to.

Comments. Flat threads appear to retard flamewars. You can also complete ignore some users. This was a feature if Kuro5hin originally I think.

One hole I see that will be improved, no doubt, going forward is that often there are users voting for stories liking the headline and not actually knowing enough about niche topics to tell if the story is actually worth voting for. People still like to judge a book by its cover.

All that being said I predict a big year ahead for Digg, not that that is hard to do, and tough times ahead for not just slashdot, but many editorially top-down websites.

James Britt

AddThis Social Bookmark Button

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

AddThis Social Bookmark Button

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.

Steve Mallett

AddThis Social Bookmark Button

1) Blogging hype will finally die down, the throngs over 25 that flocked to blogging will cease, those under 25 who haven’t blogged yet will pick up the difference, blogs continue to be incredibly useful despite so many pronouncements of its eminent death.

2) There will be funded Linux start-ups whose demise will result is people pronouncing Linux’s death in the enterprise. Self-funded/bootstrapped Linux companies will do just fine. Linux will continue unabated.

3) Many popular tech websites will shutter or retool for major ‘web 2.0′ features hoping against hope that they can survive all their readership hanging out at Digg. Expect Digg-like niche sites to pop up all over.

4) Sites will develop additional, for-pay, premium content as ad revenues decline. See prediction number 3.

5) A no-fees E-Bay killer will emerge.

6) “iPod Invisa“. Just kidding.

7) Expect Apple lawsuits over hackers getting OS X to run on commodity hardware.

8) Microsoft will begin divulging a plan to give Windows away super-cheap, integrating mandatory for-pay services like security or something resembling it.

9) Ubuntu will continue to dominate the Desktop Distro wars.

10) Desktop users will get either bigger or more screens as prices drop. Laptop users will begin moving to something smaller than a 12″ iBook, but bigger than a Treo, laptop/handheld hybrid. Nokia or Apple will pioneer it.

11) A successor to Google search will emerge among alpha-geeks. Google doesn’t worry, rolls around in adsense money.

Steve Mallett

AddThis Social Bookmark Button

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.

James Britt

AddThis Social Bookmark Button

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.
Gregory Brown

AddThis Social Bookmark Button

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 :)

James Britt

AddThis Social Bookmark Button

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.

Gregory Brown

AddThis Social Bookmark Button

    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