Sunday, November 22, 2009

Learning Japanese, I Think I'm Learning Japanese ...

The gauntlet is thrown.

In my prior blog post about the disappointing contents of some of the sessions at day one of RubyConf 2009 (which is a great conference overall, btw; try to go next year!), I mentioned that some of the presentations were below a standard that I would have expected at the premier international conference for this language/community. As it happens, all of the presenters of the sessions I called out speak English as a second language, and they are all in fact Japanese.

In my defense, I was not talking about the presenters' English skills. Lord knows their English is better than my (heretofore non-existent) Japanese. As an American who has made a point of learning and trying to function in the native language of the countries I've visited (Germany, France, and Italy to-date), I have nothing but respect for anyone brave enough to go anywhere and speak in a non-native tongue to an audience of native speakers.

That's why I've accepted John Mettraux's gentle challenge to gain full perspective by submitting a proposal to RubyKaigi 2010, Japan's version of RubyConf. John assures me that I would not be expected to present in Japanese, but that strikes me as being less than "full perspective". So I'm going to try to learn enough Japanese to not make a total fool of myself (assuming my proposal is accepted). If any of the three of you reading this blog (hi, Mom!) has any ideas for good learning resources, please do let me know.

Ah, but a man's reach should exceed his grasp, Or what's a heaven for? -- Robert Browning

Friday, November 20, 2009

RubyConf Day Two: I Have Seen The Future, And It Is ...

MacRuby.

So day two of RubyConf went much better for me, content-wise. Caleb Clausen gave a subdued, but very interesting, presentation on Ocelot, his version of a Ruby compiler. Yehuda Katz brought down the house with his presentation "Polishing Rubygems", which was primarily about his project, Bundler. Andy Keep had a different take on the topic of partial evaluation to make Ruby more amenable to compiling. And Charlie Nutter was very engaging in his presentation with Thomas Enebo on the status of JRuby, including a cool demo of jirb running on an Android phone (simulator).

But my favorite talk by far was Laurent Sansonetti of Apple, talking about MacRuby. Laurent, who is clearly not a native English speaker -- are you reading this, jmettraux? -- gave a professional, content-laden presentation on MacRuby, which is pretty much his baby at Apple. He had some cool demos -- one of which was nearly thwarted by the hotel's abyssmal internet setup -- of MacRuby's integration with Cocoa/Objective-C, which also demonstrated that MacRuby has already solved the problem of compiling Ruby. XCode will build executables with the MacRuby framework embedded, and it will ship the MacRuby code as binary .rbo files, not Ruby source files. No need to obfuscate or simply give your code away; MacRuby takes care of it all.

Now if only we could get Apple to open up the iPhone to this. Or perhaps build a tablet of some sort ...

Thursday, November 19, 2009

RubyConf 2009: Day One

In a word: disappointing.

Oh, the venue (the Embassy Suites at the San Francisco Airport) is nice enough. And yes, there are problems finding power and getting on the internet, but that's to be expected. Anyone who attends a gathering of more than about ten people and actually believes the claims of abundant power and speedy WiFi for all is asking for a let-down. So it's not that.

Maybe it was just my bad luck in the sessions I chose to attend. I was very much looking forward to hearing some of the Ruby core team speak, so I made sure to catch Matz's keynote, "East meets West", and "Hacking parse.y", the latter being interesting to me in its own right since it was about Ruby implementation internals.

Matz has decent presence as a speaker, and the crowd dutifully laughed at all his good-natured, pro-forma digs at other languages' foibles (Java is lame. Lisp has too many parentheses. Et cetera.). But he didn't have anything particularly new or interesting to say about Ruby or language design, just that there can be no "one true" programming language, that the best we can hope for is one that's "close enough", and in his opinion Ruby is currently the best candidate. Go figure. Still and all, the man did invent the language that I currently use to make a living, so major props to him.

The other two were just not up to any reasonable standard for a conference at this level.

Look -- I know the Ruby community prides itself on being edgy. I get that RubyConf is deliberately kept small and scruffy and non-RailsConf-y. But is it really asking so much that the people who present talks at The Premier Conference for their language/community have some basic skill in the art of talking to an audience?

I did find the talk on using Ruby to write DSLs and code generation tools for hybrid systems simulation and scientific computing pretty interesting. And tomorrow's schedule looks good on paper.

Here's hoping it goes better than today.

Wednesday, November 18, 2009

Dear RVM: It's Not Me. It's You.

Dear Ruby Version Manager,

It's over. I tried. But I just can't do it any more. I though I could let you back into my life after that unfortunate 'sudo gem install rvm' spat we had on our first date. That's on me. But even after I moved you into my home directory, you still couldn't make it work.

I wanted it to work. Really, I did. I mean, a chance to have an open relationship with multiple Ruby's, all painlessly and seamlessly installed and switchable through you? Who wouldn't want that?

But you just couldn't handle my prior relationship with my self-compiled, self-installed /usr/local/bin/ruby, could you? I mean, you ... you ... it hurts just to type it ... you hijacked my $PATH, RVM! You locked me out of my gems! I mean, they weren't all switchable and fancy and all, they were just plain gems, but they were my gems, you know? How was I supposed to trust you after that?

Was it jealousy? Was it ignorance? I guess I'll never really know.

But -- for now at least -- I have to give you up. I have to lash myself to the mast of my virtual Argo, and forego your sweet, seductive siren song.

It's a pity. We could've been something, you and me.

Wednesday, October 14, 2009

Ruby's inject(): Putting the 'Fun' in 'Functional Programming' Since ... Oh, About 4:15 This Morning

Yesterday at work, I ran across the need to convert a number of seconds into its equivalent in days, hours, minutes, and seconds. The canonical imperative way to do this is something like:
seconds = 356521
days = seconds / (24 * 60 * 60)
seconds = seconds % (24 * 60 * 60)
hours = seconds / (60 * 60)
seconds = seconds % (60 * 60)
minutes = seconds / 60
seconds = seconds % 60
N.B.: This relies on Ruby's integer division -- dividing an integer by an integer results in an integer, with any fractional remainder discarded.

My pair and I ended up implementing something very much like this, but it left a bad taste in my mouth. I mean, it works and all, but it feels kind of ... non-functional. Ya know?

So, after much fretting and sleeplessness last night ... behold:
seconds = 356521

days, hours, minutes, seconds =
[1.day, 1.hour, 1.minute, 1.second].inject([]) do |acc, unit|
quotient, seconds = seconds.divmod unit
acc << quotient
end
This version needs to be run in a Rails script/console rather than irb, because it makes use of the Rails shortcut definitions of the number of seconds in various units of time. You could easily convert to plain irb-able Ruby by replacing 1.day et al above with their numeric equivalents.

The resulting code is both (more) functional, and more quintessentially Ruby-ish. divmod and multiple assignment let us figure out the quotient and the remainder of the division in one go, and inject lets us accumulate the results and ultimately multiply assign them to their respective units.

Neato.

I'm a little bummed, though, that this version has the side effect of destroying the original contents of seconds, as well as requiring seconds to be defined outside the scope of the inject. What would be really cool would be to have a version of inject that allowed for multiple accumulators (or, really, a 'decumulator' in this case) such that all side effects could be contained within the inject.

Wednesday, September 09, 2009

Fun With Metaprogramming: hash_initializer()

Earlier this week I was doing a code review for a candidate for ThoughtWorks. One of the bits I ran across was an object constructor that looked something like this:

class MyClass
def initialize(name, price, is_cool, is_neato, is_rad)
@name = name
# et cetera
end
end

Not so bad, really, when you're looking right at the signature for the constructor. But when it's called from another file...

MyClass.new("bob", "1.00", true, false, true)
MyClass.new("fred", "2.00", false, true, true)
# et cetera

... the purpose of the first two parameters may be easy to infer, but the last three? Which order were those descriptors in anyway? To really be sure, one has to keep referring to the class definition. In my review, I opined that perhaps the constructor should take a single argument -- a hash with keys named after the objects instance variables and their corresponding values. Thusly:

class MyClass
def initialize(args)
args ||= {} # in case MyClass#new is called without any args
@name = args[:name] || ""
# et cetera
end
end

This frees things up a bit, and allows for parameters to be specified in any order, with reasonable defaults for any that might be left out. It also makes calls to the constructor a little more self-documenting.

But what would really be nice would be not having to write out this boilerplate code for everything that we want this kind of constructor for.

Enter metaprogramming, in the form of hash_initializer -- a nifty little class extension I found in Brian Guthrie's Awsymandias library (as used at my current ThoughtWorks gig). Behold:

1. module ClassExtension
2.
3. if !Class.respond_to?("hash_initializer")
4. def hash_initializer(*attribute_names, &block)
5. define_method(:initialize) do |*args|
6. data = args.first || {}
7. data.symbolize_keys!
8. attribute_names.each do |attribute_name|
9. instance_variable_set "@#{attribute_name}", data[attribute_name]
10. end
11. instance_eval &block if block
12. end
13. end
14. end
15.
16. end
17.
18. Class.send :include, ClassExtension

Lines 5 through 12 correspond pretty much to my second version of MyClass#initialize above. Line 6 does the same defensive guard against a nil first parameter. Lines 8 through 10 pull each attribute, create an instance variable with the same name, and set it to the desired value. The extra bits? Line 7 does something I should have done in my "improved" version -- it forces the keys of the params has to be symbols, avoiding the awkwardness of blowing up when a key is a String when it should be a symbol or vice versa. Line 11 allows for the execution of a block along with initialization, if you're into that sort of thing. And the rest just opens up the class Class and makes Class#hash_initializer available to all objects.

With Class thus extended, the boilerplate for MyClass becomes simply:

class MyClass
hash_initializer :name, :price, :is_cool, :is_neato, :is_rad
end

And instantiating a MyClass stays what you would expect:

MyClass.new :name => "bob", :price => "1.00" # et cetera.

I like it.

irb(main):001:0> Class#hash_initializer.is_neato?
=> true

Monday, August 10, 2009

Code Artistry: The Negative Space

So I've been reading The Merb Way this week. I like it so far -- Foy Savas does a pretty good job of making his discussion of the technical internals interesting to read, and generally elevates the material above today's standard grind-it-out, dress-up-the-man-page-or-the-public-API-docs, tech book farce. Fare. I meant "fare".

One of the standout features of this book, though, that I'm finding myself drawn to is a marked lack of comparison between Merb and Rails. I can't tell if Savas intended this, but I find reading about, say, Merb's routing architecture easier to follow than if it were interrupted every other paragraph by an "as compared to Rails, which does this..." interlude. I'm not sure many other authors would have avoided that trap as neatly.

If you think about it, it's a sensible approach to take, although maybe not the most obvious one. If I'm reading a book on Merb, what I want to read about is ... you know ... Merb. I may already know some of the internals of Rails. I may not. If I do, chances are that I will make those comparisons myself. If I don't, chances are a constant barrage of interruptions would just turn me off of Merb, and possibly Rails too. Either way, interleaving a discussion of Rails within a discussion of Merb would be counterproductive.

Reading this book makes me wish more of us technologists would learn the value of the artistic concept of the negative space -- the bizarre and intriguing shapes formed *between* the familiar ones that are the nominal focus of the picture. That what the artist leaves out can contribute as much to the picture as what he puts in. Sometimes more.

I was going to write out a list of how this concept applies to and enhances other artistic and quasi-artistic disciplines like architecture, music, literature, and film-making.

But now I'm not. :-)