- Beta 1 of VS “Orcas” and .NET Framework 3.5 has shipped. Get it here. Besides LINQ, I’m most looking forward to experimenting with some of the new WF/WCF integration work. However, I don’t think this beta includes DBPro functionality. Not surprising, given that DBPro only shipped a few months ago, but disappointing since I’ve moved all my database dev work over to that model.
- Korby Parnell introduces Claimspace, part of the Microsoft.Community family. While the other family members are retreads – blogs, forums and tagging – but this seems like something fundamentally new – or at least new to me – and therefore interesting. (via Larkware)
- Scott Hanselman updates the new version of Notepad2 to re-enable Ruby support originally built by Wesner Moise. Ruby is nice, but where’s the PowerShell love?
- After his performance in front the Judiciary Committee, Attorney General Gonzales is grossly incompetent, lying or both. What does it say about President Bush that he was “pleased with the Attorney General’s testimony“? It says Bush values loyalty over competence, is hiding something or both. Given that his approval ratings can’t get much worse, I guess standing by Gonzales even in the midst of bi-partisan calls for his resignation isn’t going to affect Bush much politically. On the other hand, confirming a new AG with a Democratic congress and low 30% approval rating might be devastating, depending on the bodies buried over there.
Morning Coffee 67
Morning Coffee 60
My car has a new battery so I am back in the office with my nose on the grindstone. I’ve spent most of the morning talking about SOA and my MSIT project, so I only have a few items today.
- Nicholas Carr illustrates the coming competiton between SalesForce.com and Google. Very interesting. Of course, that doesn’t damp “their mutual disdain for the Horrible Monster of Redmond” as Carr puts it.
- I decre that Peter Schneider officially has too much time on his hands. I mean, if he’s got time to implement a compiler and interpreter for Brainfuck in Powershell, what else has he got time for? On the other hand, it’s short and shows how internal DSL friendly PS can be. (via Larkware)
- Jeff Atwood wonders if MTurk is a failure. I wrote a year ago that MTurk is a successful feature, but would be a failure as a stand-alone service. As I wrote then, “I’m guessing it would be worth it to Amazon to run the service even if they were the only ones using it.”
Morning Coffee 46
Sort of late this morning due to back to back meetings…
- I seem to have stirred up a bit of a hornet’s nest with my “kinda surprising that no other mainstream language has done this before” comment. Dennis Hamilton and Mike Parsons both asked about other dynamic languages like Javascript and Python in my comments. To be clear, the ability to add a new method to a specific object instance is fairly common in dynamic languages. Extension methods in C#3/VB9 is a different capability – it only supports adding new methods to a class, not to specific object instances. I’m not sure what dynamic languages other than Ruby supports adding new methods to both object instances and classes, but I’m sure they’re out there.
- Some anonymous commenter asked “why invent another language for PowerShell if there are so many great popular languages already in existance [sic]?” I can’t speak for the PowerShell team, but I think they were better off inventing a new language specificly designed for their scenario than they would have been shoe-horning in existing lanugage. To their credit, it looks like the PS team took great care to make the PS lanugage accessable by leveraging common syntax and idioms from other shell programming environments. I’m not a shell programming expert, but isn’t PS more a variant of shell languages that have come before than a brand new language?
- I want a “Works on My Machine” T-Shirt.
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.