I’m Wrong Because Ruby and Powershell Are Mainstream

Brad Wilson and Scott Hanselman took me to task for my comment the other day that no “mainstream” language had implemented extension methods:

How mainstream is Ruby on Rails for you? Ruby is a full fledged dynamic language. No hacks for “extension methods” (Brad)

Ya, I kind of blanched at that statement too…method_missing is pretty mainstream… (Scott)

They’re right, Ruby does support the addition (and redefinition I think) of methods on a class at any time. There’s a sample of this in the Classes and Objects chapter of Programming Ruby (aka the pick-axe book) where they add a basic documentation facility “available to any module or class” in Ruby by adding a doc instance method to the Module class.

class Module
  @@docs = Hash.new(nil)
  def doc(str)
    @@docs[self.name] = str
  end
  def Module::doc(aClass)
    # If we’re passed a class or module, convert to string
    # (‘<=’ for classes checks for same class or subtype)
    aClass = aClass.name if aClass.type <= Module
    @@docs[aClass] || “No documentation for #{aClass}”
  end
end

Given how Ruby classes are defined, I think the newly added methods have access to the private data of the class. Extension methods in C#3/VB9 only have access the public interface of the object. But that’s a fairly minor difference.

FYI, Powershell can do this as well, though not as succinctly as Ruby. Scott has an example how you can add a DatePhotoTaken property to System.IO.FileInfo using Omar Shahine’sPhotoLibrary project.

Chalk this up to my continuing ignorance of dynamic languages. I’m working on it, albeit slowly.

Internal DSLs in PowerShell

(Harry is on a secret mission in uncharted space this week, so instead of the daily Morning Coffee post, you get a series of autoposted essays. This post combines both some leftover learnings about Ruby from Harry’s Web 2.0 days with his recent obsession with PowerShell.)

My first introduction to the idea of internal DSLs was an article on Ruby Rake by Martin Fowler. Rake is Ruby’s make/build utility. Like most build tools like Ant and MSBuild, Rake is a dependency management system. Unlike Ant and MSBuild, Rake doesn’t use an XML based language. It uses Ruby itself, which has huge benefits when you start doing custom tasks. In Ant or MSBuild, building a custom task requires you to use a external environment (batch file, script file or custom compiled task object). In Rake, since it’s just a Ruby file, you can start writing imperative Ruby code in place.

Here’s the simple Rake sample from Fowler’s article:

task :codeGen do  
  # do the code generation
end

task :compile => :codeGen do  
  # do the compilation
end

task :dataLoad => :codeGen do  
  # load the test data
end

task :test => [:compile, :dataLoad] do  
  # run the tests
end

The task keyword takes three parameters: the task name, an array containing the task dependencies and a script block containing the code to execute to complete the task. Ruby’s flexible syntax allows you to specify task without any dependencies (:codegen), with a single dependency (:compile => :codegen), and with multiple dependencies (:test => [:compile,:dataLoad])

So what would this look like if you used Powershell instead of Ruby? How about this:

task codeGen {  
  # do the code generation
}
task compile codeGen {
  # do the compilation
}

task dataLoad codeGen {  
  # load the test data
}

task test compile,dataLoad {
  # run the tests
}

Not much different. PS uses brackets for script blocks while Ruby uses do / end, but that’s just syntax. Since it lacks Ruby’s concept of symbols (strings that start with a colon), PS has to use strings instead. Otherwise, it’s almost identical. They even both use the # symbol to represent a line comment.

There is one significant difference. For tasks with dependencies, Rake uses a hash table to package the task name and its dependencies. The => syntax in Ruby creates a hash table. Since the hash table has only a single value, you can leave of the surrounding parenthesis. The key of this single item hash table is the task name while the value is an array of task names this task depends on. Again, Ruby’s syntax is flexible, so if you have only a single dependency, you don’t need to surround it in square brackets.

In Powershell, the hash table syntax isn’t quite so flexible, you have to surround it with @( ). So using Rake’s syntax directly would result in something that looked like “task @(test = compile,dataLoad) {…}” which is fairly ugly. You don’t need to specify the square brackets on the array, but you having to add the @( is a non-starter, especially since you wouldn’t have them on a task with no dependencies.

So instead, I thought a better approach would be to use PS’s variable parameter support. Since all tasks have a name, the task function is defined simply as “function task ([string] $name)”. This basically says there’s a function called task with at least one parameter called $name. (All variables in PS start with a dollar sign.) Any parameters that are passed into the function that aren’t specified in the function signature are passed into the function in the $args variable.

This approach does mean having to write logic in the function to validate the $args parameters. Originally, I specified all the parameters, so that it looked like this: “function global:task([string] $name, [string[]] $depends, [scriptblock] $taskDef)”. That didn’t work for tasks with no dependencies, since it tried to pass the script block in as the $depends parameter.

Here’s a sample task function that implements the task function shown above. It validates the $args input and builds a custom object that represents the task. (Note, the various PS* objects are in the System.Management.Automation namespace. I omitted the namespaces to make the code readable.)

function task([string] $name) {
  if (($args.length -gt 2) -or ([string]::isnullorempty($name))) {
    throw "task syntax: task name [<dependencies>] [<scriptblock>]"
  }
  if ($args[0] -is [scriptblock]) {
    $taskDef = $args[0]
  }
  elseif ($args[1] -is [scriptblock]) {
    $depends = [object[]]$args[0]
    $taskDef = $args[1]
  }
  else {
    $depends = [object[]]$args[0]
    #if a script block isn't passed in, use an empty one
    $taskDef = {}
  }

  $task = new-object PSObject
  $nameProp = new-object PSNoteProperty Name,$name
  $task.psobject.members.add($nameProp)
  $dependsProp = new-object PSNoteProperty Dependencies,$depends
  $task.psobject.members.add($dependsProp)
  $taskMethod = new-object PSScriptMethod ExecuteTask,$taskDef
  $task.psobject.members.add($taskMethod)
  $task
}

Of course, you would need much more than this if you were going to build a real build system like Rake in PowerShell. For example, you’d need code to collect the tasks, order them in the correct dependency order, execute them, etc. Furthermore, Rake supports other types of operations, like file tasks and utilities that you’d need to build.

However, the point of this post isn’t to rebuild Rake in PS, but to show how PS rivals Ruby as a language for building internal DSLs. On that front, I think PowerShell performs beautifully.

I’m looking forward to using PowerShell’s metaprogramming capabilities often in the future.

Morning Coffee 28

  • From the “Ask and ye shall receive” department: A couple weeks ago I wondered how good or bad my Gamerscore conversion rate is. MyGamerCard.net just launched a completion leaderboard where they rank you on your Gamerscore times your completion rate.
  • Shane Courtrille pointed out that the prize you receive in from the Xbox Rewards program gets better if your Gamerscore is higher. With a meager 1090 points, I’m in level 1. But those with 10,000+ or more can get a copy of Fuzion Frenzy 2 for completing the challenge.
  • Yesterday, I complained that code in my RSS feed looks awful. It appears to be a problem with dasBlog. In validating the HTML is actually XHTML, it screws up the white space. Of course, usually that’s not a big deal, but inside a <pre> tag, it is. Until I get a chance to submit a patch to dasBlog to fix this, I’m using CodeHTMLer, which has a “convert white space” option that doesn’t use the <pre> tag at all. As a bonus, it even support PowerShell! Note, you have to use the website, not their WLWriter plugin, if you want the convert white space option.
  • There’s a new beta of Ruby.NET available. Now that I’ve moved on to PowerShell, I’m only slightly interested in Ruby these days. If I can figure out how to create internal DSLs with PS, what would I need Ruby for? (via Larkware)
  • My old team just shipped a single-instance multi-tenancy SaaS sample called LitwareHR. Details are on Gianpaolo’s blog, code is up on CodePlex.

Alpha Release of Ruby.NET

I’m not sure what a “Preliminary Beta” is but QIT has released a one for their Ruby.NET compiler. They expect to achieve “full semantic compatibility” (can you tell this is an acidemic project?) by the end of the year. Thanks to David Ing for the link.

They claim to “pass all 871 tests in the samples/test.rb installation test suite of Ruby 1.8.2.” which seems odd since later they say “We have a plan for how to deal with continuations but we have not yet implemented them.” Doesn’t the Ruby test suite test continuations? I wish they would provide more details on this plan, continuations might not be the most interesting thing in Ruby, but it’s up there and it’s probably the hardest thing to implement on top of the CLR.

BTW, there are two other projects @ QIT that Ruby.NET leverages that look interesting. The Gardens Point Parser Generator is essentially a YACC clone written in C# and making extensive use of generics. Personally, I’m more interested in Parsing Expression Grammars, but there’s no C# implementation as of yet. QIT also has a library for reading and writing program executable files (i.e. EXEs and DLLs).

As a quick aside, I’m getting pretty tired of all the different euphemisms for “alpha”. In the age of perpetual beta, isn’t alpha the new beta? But everyone seems worried about calling their releases alpha as if it means “it might not cause your machine to explode, if you could actually get it to compile”. So we end up with things like “Preliminary Beta” and “Community Tech Preview”. We all KNOW what these terms mean, so lets just call an alpha and alpha, shall we?

ActiveRecord::Migration

When I wrote about the Dual Schema problem a few weeks ago, I specifically wrote that the Rails model is backwards because it derives the in-memory schema from the database schema. While I still believe that, Rails’ ActiveRecord::Migration library does make it significantly easier to manage the database from Ruby code. For those not familiar, ActiveRecord::Migration is a series of Ruby script files that define the database schema. Inside each migration script is an up and down method, so you can migrate forward and backward in the history of your project. And it provides easy to use abstractions such as create_table and add_column so you don’t have to geek out on SQL syntax (unless you want to). Once you have a collection of these scripts, simply calling rake migrate will bring your database instance up to the current schema (rake is Ruby’s equivalent of make). Or, you can set your database to a specific version of the schema by running rake migrate VERSION=X.

I wonder why the Rolling on Rails tutorial uses the database tools directly instead of ActiveRecord::Migrate? I’m thinking it wasn’t available when the tutorial was written. Whatever the reason, they really should update the tutorial to reflect the current state of Rails.