Thursday, March 27, 2008

Adventuress Crew

After helping with maintenance on Adventuress, I agreed to be a tester for their new web site. The first thing I saw was an announcement that they'd be training volunteer crew. Volunteer crew? Perfect!

I spent a Saturday on board in training, which included a sail around the bay.

The next day was the first public sail of the season. Since my family is a member of Sound Experience, we got to come on for free. We set up the bicycle train & all 5 of us rode down. The twins explored the cabins, including standing on my shoulders to peek out the focsle hatch. They eventually fell asleep as the trip was coming to an end - great timing! Reid got to look at plankton in a Microscope.

Monday I took Reid to his homeschooler's gymnastics class. It's held in the post office building, of all places, which is a fancy, century-old structure perched up high over the bay. From there I got to watch Adventuress sail around while he was in class.

Monday night I looked at Adventuress' schedule and saw that there wouldn't be many opportunities for me to volunteer, so I better get with it. They sail from a variety of ports, but only a handful of trips are from Port Townsend. They do day sails for a few hours, as well as 3-7-day trips, but I don't think I can fairly leave the family overnight.

First chance was Tuesday. So I showed up at the docks Tuesday morning, and they said they'd put me to work. It turns out that the group that was coming out was a homeschooling group, some of which had been at the gym class the day before. Funny.

Next chance was a public sail on Saturday, but we were out of town for a birthday party.

Easter Sunday we planned to do an egg hunt, but it was rainy, so we had a small event in our living room. Then I headed down to the docks for a public sail that afternoon. It was a pleasant sail, with enough wind to get us going, but not enough to make it "interesting". That is, until we were putting the sails away. We were training to furl the enormous mainsail, when a squall hit, and winds climbed to about 25mph. We could barely get the main under control, and it was suddenly cold, dark, and rainy to boot. When we were back at the docks, the weather cleared up, and we did what we could to make the boat neat -- shipshape.

Monday was the last day sail I can do for a while. It started off well for me. As soon as I stepped on board, I got to climb on top of the main gaff to downrig some extra lines they had placed up there for the wind. I enjoy the feeling of being able to climb; something I used to think I couldn't do. The participants were school kids, mostly 8th graders, who had come all the way from Yakima. It was quite a full ship, with 45 kids + 2 adults + crew. When we were headed back to the docks, I got to take the "small boat ride", zooming along in a little inflatable dingy, to be dockside when adventuress came in. Weee! When we were furling the staysail, we all sang "lean on me". There's a lot of music on Adventuress, and I love singing, but I'm not used to doing it with any kind of audience. Maybe in time... At the end of the day, I said my thanks and good-byes to the crew, and they responded quite heartily.

Wednesday there was a postcard from Adventuress, signed by many of the crew & staff, saying thanks.

I love the fact that we both feel indebted to each other. I am grateful for my chance to go sailing, to learn so much more about sailing in general, and this boat in particular, to see this beautiful ship in action, and to give others (passengers) the chance to get on the water, as well. I know that Adventuress & Sound Experience benefit as well: they got my help, and I know that organizations like this also feed on the energy that volunteers bring. Mutual indebtedness is the basis of a strong community. Bring it on.

At the beginning of May they'll be back in PT for a day; I hope I get to go out with them again then. After that, it's September, around the Wooden Boat Festival.

Monday, February 25, 2008

Adventuress maintainance

Reid & I spent Sunday working on Schooner Adventuress. I had the opportunity to sail on her a couple years ago, and when I moved to Port Townsend, I was looking forward to the opportunity to connect with them again.


They do maintainance work over the winter, and invite folks to volunteer for a "work weekend" each month. We went to help in January. Reid found another kid & the two of them played. I watched the kids & sorted the fasteners (huge collection!).


This time I spent the morning scuffing the varnish on the deckhouse, in preparation for a new coat. They were getting ready to sway up the main boom, and Reid helped tie some lines on for the purpose. He learned the marlinspike hitch and put it to good work.


The afternoon was spent with spars. The main boom and main- and fore-topmasts were stowed on deck, being the most unwieldy (least wieldy?). We swayed up the main boom, with folks pulling on lines in 8 directions to keep it under control.


Once it was secured, we were sent to "spar land" (a storage space far away) to get the other 4 large spars - main gaff, fore gaff, fore boom, and "club" (which I'd call the jib boom, but what do I know?) . They had a dolly made of the rear axel + wheels of a car w/ a small superstructure. A spar was hauled out of the shed (up to 8 people to lift them) and balanced on the dolly; a second spar placed next to it. We then walked the spars to the dock, and carried them down the dock to the boat. My shoulder has a sore, red area from bearing the weight.


Once the spars were placed on deck, we cleaned up and called it a day. The crew of Adventuress will sway up the remaining spars on their own, they being much smaller than the main boom.

Thursday, February 21, 2008

The end of the world as we know it

Every time I read something by Charles Eisenstein, I love it.  I usually feel like he's saying what I want to say, but I don't even know it. 
 
Yesterday I read his Waiting for the Big One, and it was no disappointment.  I particularly liked his list of "doom and gloom credentials", which begins with:

First and foremost, I am aware of the environmental crisis: climate change, desertification, coral bleaching, tree death, topsoil erosion, habitat destruction, irreversible loss of biodiversity, toxic and radioactive waste, the PCBs in every living cell, the vast swaths of disappearing rainforests, the dead rivers, lakes and seas, the slag heaps and quarry pits, the living world reduced to profit and pavement.

I am aware of Peak Oil and the dependency of all aspects of our economic infrastructure and food supply on fossil fuels. And I realize that no conventionally-recognized alternative energy source can possibly hope to replace oil and gas any time soon.

and goes on and on.  In my printed copy, this list filled 2 pages.  
 
A couple years ago I went to an unconventional doctor who claims to be able to ask your electromagnetic aura questions, and get answers.  Things like "is mercury in your body the cause of that skin condition?".  I was sick at one point, and he suggested an antibiotic.  I told him that I try to avoid antibiotics, and so he asked my aura which of several treatments I should choose, to balance my principles & need for treatment.  The answer was grape seed extract.
 
I have no idea what an "electromagnetic aura" is. I'm generally a rational science-loving type of person, and nothing that he does fits in to my understanding of how the world works.  5 years earlier I would have laughed at him and gone on with my life.  But, thanks largely to Charles Eisenstein's writings, I've learned that there is dramatically more truth than science can find.  Science has strict rules about what it can do, which is fundamental to why science is great, but it's also very limiting.  If we lived our lives relying only on scientifically-proven truths, we would live incomplete lives.  At some point you have to make a decision based on something else.  That something else is "faith", although I hesitate to use the word.  I don't mean "things you believe regardless of contradicting evidence", but "things you believe when evidence can't help".  I can't prove that this doc is a quack; I can't prove that he's able to do what he claims to do.  I know that I need more than what conventional medicine can offer, so I accept what he tells me.
 
I've been suffering from restless legs since I was a teenager (now it has a name & web sites & there's medication, but for a long time I couldn't even explain it to people around me.)  This doc told me that it was emotional; that I am angry; that the target of my angry is mankind in general; that I am angry that people could act so badly, and allow people to act so badly. 
 
He's right that I have this anger, but I hadn't really identified it before.  However, when I read through Eisenstein's list yesterday, it suddenly made a lot more sense.  That list is exactly what I am angry about.  He nailed it for me, exactly.  It was an intense experience for me to see the list, and see the complete outline of my frustration.  I plan to read through it again, to see where it takes me.

Monday, February 18, 2008

Dear Diary

Good sleep last night.  The baby slept on my from 11pm to 7am or so.  Then Julie kept the twins while I slept another 90 minutes.  Still tired, but Julie is sick & shoulda been the one to sleep in.  Found that last night's chicken noodle soup (what's a chicken noodle?) was out all night; put it on LO to simmer until lunch time.  Breakfast as usual (eggs w/ sausage & cheese, tea w/ milk and honey, toast w/ butter & jam). 
 
Clear skies & sun.  Took the kids out to play on the bike while Julie slept.  Pulled all 3 in the bike trailer over to the house with chickens. No one home, so we rode on through the neighborhood, and then home.  Zephyr & I played outside another 1/2 hour.  He says "bike" now, but says it as "kai-ka", after Dylans "bike-a".  Cleaned the garage & prepared the speakers for sale.
 
Got Home Server back on line.
 
Lunch of hot, dense, overcooked, delicious soup.  Played Black and White 2 Demo with Reid while everyone else slept.  Kids now watching Curious George.  Again.  Gonna play a little more now.
 
Tomorrow is a big day. Doctor; Laurel arrives.  Must clean a bit. 

--
-Jay

Monday, February 11, 2008

Dylan, Zephyr, and Terra


They were cute. My camera phone's color correctness is disappointing, but I think it still works.


Tuesday, January 22, 2008

Port Townsend construction irony

This morning we awoke to find conutility workerrs outside our house.  There are a bunch of trucks with flashing lights.  All the workers are wearing bright orange vests.  Two guys are holding those stop/slow signs at the ends.
 
The irony is that traffic on this street is so very, very light.  A couple cars per hour is normal here.

Thursday, January 10, 2008

Signs of Port Townsend: Getting to the library

One of the reasons I was looking forward to moving to Port Townsend was that I was hoping for a place where I could live without the car. So far it has gone well - the car pretty much sits in the driveway, untouched for days.

Today we walked to the library for a story time event for toddlers. We put the twins in the double stroller for the trip there. When we arrived, we saw 3 strollers already parked outside. I think that's a good sign.

On the way home, Zephyr refused to ride in the stroller. As he walked, he stopped at each puddle, observed the relationship between the reflection and the real objects, dropped a rock in & observed the corruption of the image, then picked up the rock and walked on. He had a fantastic time. When he got home, he was cold & wet, but 15 minutes later he was warm & asleep.

Thursday, December 13, 2007

Biking the wrong way

Today I drove the U-Haul truck from Port Townsend to Sequim to drop it off. My plan was to bring my bicycle along, bike from the drop-off to the bus stop, and catch the bus back home. This bus only runs about every 3 hours, so it was important to time things correctly. I failed.

First, I didn't have internet access working in the new house, so I couldn't look up bus info, and couldn't remember it well.

Second, I wasn't paying attention to the clock.

Third, I rode my bike on the wrong path. Here's what I could have done:


View Larger Map

(Assume I cut across that sharp left turn that Google Maps won't let me do, because it thinks this is for a car.)

But I turned left too early, and meandered around for a while. Here's what I did instead:


View Larger Map

That's 7.5 miles. I'm pretty impressed with myself, considering how long it has been since I was in shape, and how, with the move & everything, the last couple months have been little exercise and a gain of 10 pounds.

And then, after the bus ride, I rode the bike up the big hill to the house.

And then, I put the babies in the stroller, and walked to the grocery store to get dinner for the family.

I'm feeling proud of myself, and very hopefull for my future exercise.

Saturday, December 08, 2007

An attempt at an immutable Queue

Eric said he will write about an immutable queue implementation. I really like the way the immutable stack turned out, essentially using references between Stack<> objects to implement a linked list, but I couldn't figure out a similarly elegant way to do the same thing for Queue. Maybe people who are more clever will come up with something better, but I just had each Queue<> object contain a list of references to elements.

I wrote once in C# 2.0, using an array to store the elements. The code would be cleaner if I used a List<>, but then I would be harder to verify immutability.

class Queue<T> : IQueue<T>

{

public static readonly IQueue<T> Empty = new Queue<T>(new T[] { });


 

readonly T[] elements;


 

Queue(T[] elements)

{

this.elements = elements;

}

public bool IsEmpty { get { return this.elements.Length == 0; } }

public T Peek() { return this.elements[0]; }

public IQueue<T> Remove()

{

T[] newElements = new T[this.elements.Length - 1];

Array.Copy(this.elements, 1, newElements, 0, newElements.Length);

return new Queue<T>(newElements);

}

public IQueue<T> Add(T value)

{

T[] newElements = new T[this.elements.Length + 1];

Array.Copy(this.elements, newElements, this.elements.Length);

newElements[newElements.Length - 1] = value;

return new Queue<T>(newElements);

}

public IEnumerator<T> GetEnumerator()

{

for (IQueue<T> Queue = this; !Queue.IsEmpty; Queue = Queue.Remove())

yield return Queue.Peek();

}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }

}

Then I rewrote using C# 3.0, taking advantage of the rich support for sequences. The code is much simpler, but I think that's basically because the IEnumerable extension methods do pretty much what I did in my first attempt. But I'll take it. J

class Queue2<T> : IQueue<T>

{

readonly IEnumerable<T> elements;


 

public static IQueue<T> Empty = new Queue2<T>(new T[] { });


 

Queue2(IEnumerable<T> elements)

{

this.elements = elements;

}


 

IQueue<T> IQueue<T>.Add(T value)

{

return new Queue2<T>(this.elements.Concat(new T[] { value }));

}


 

IQueue<T> IQueue<T>.Remove()

{

return new Queue2<T>(this.elements.Skip(1));

}


 

T IQueue<T>.Peek()

{

return this.elements.First();

}


 

bool IQueue<T>.IsEmpty

{

get

{

return this.elements.Count() == 0;

}

}


 

IEnumerator<T> IEnumerable<T>.GetEnumerator()

{

return this.elements.GetEnumerator();

}


 

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()

{

return this.elements.GetEnumerator();

}

}


 


 


 


 

Saturday, November 24, 2007

Immutable data class generator: it lives!

Well, it works. You invoke like this:

. .\Library.DataClass.ps1

class MyClass {

    field ([string]) S

    field ([int]) I

} > MyClass.cs

And then you can write:

MyClass mc = new MyClass.Builder().SetS("xxx").ToMyClass();

MyClass mc2 = new MyClass.Builder(mc).SetS("yyy").ToMyClass();

And the output looks like:

internal partial class MyClass

{

public readonly System.String S;

public readonly System.Int32 I;


 

public MyClass(string S, int I)

{

this.S = S;

this.I = I;

}

public class Builder

{

public string S;

public int I;

public Builder()

{

}

public Builder(MyClass value)

{

this.S = value.S;

this.I = value.I;

}

public virtual MyClass ToMyClass()

{

return new MyClass(this.S, this.I);

}

public virtual Builder SetS(string value)

{

this.S = value;

return this;

}

public virtual Builder SetI(int value)

{

this.I = value;

return this;

}

}

}

The main issue is that the ToMyClass and Set* methods are virtual. I think I may be hitting a bug in PowerShell, but I'm still researching it. For now, this will have to do.

Here's the implementation of Library.DataClass.ps1:

function Class

{

    param (

        [String] $name,

        [ScriptBlock] $memberScriptBlock

    )


 

    $class = New-Object System.CodeDom.CodeTypeDeclaration $name

    $class.TypeAttributes = [System.Reflection.TypeAttributes]::NotPublic

    $class.IsPartial = $true


 

    $constructor = New-Object System.CodeDom.CodeConstructor

    $constructor.Attributes = [System.CodeDom.MemberAttributes]::Public

    $class.Members.Add( $constructor ) | Out-Null

    

    $builderClass = New-Object System.CodeDom.CodeTypeDeclaration "Builder"

    $class.Members.Add( $builderClass ) | Out-Null


 

    $builderConstructor = New-Object System.CodeDom.CodeConstructor

    $builderConstructor.Attributes = [System.CodeDom.MemberAttributes]::Public

    $builderClass.Members.Add( $builderConstructor ) | Out-Null

    

    $builderConstructor2 = New-Object System.CodeDom.CodeConstructor

    $builderConstructor2.Attributes = [System.CodeDom.MemberAttributes]::Public

    $builderConstructor2.Parameters.Add(

        (New-Object System.CodeDom.CodeParameterDeclarationExpression( $name, "value" ))

    ) | Out-Null

    $builderClass.Members.Add( $builderConstructor2 ) | Out-Null

    

    $realizeMethod = New-Object System.CodeDom.CodeMemberMethod

    $realizeMethod.Attributes = [System.CodeDom.MemberAttributes]::Public

    $realizeMethod.Name = "To$name"

    $realizeMethod.ReturnType = $name


 

    $ctorExpression = New-Object System.CodeDom.CodeObjectCreateExpression

    $ctorExpression.CreateType = New-Object System.CodeDom.CodeTypeReference($name)

    $realizeMethod.Statements.Add(

        (New-Object System.CodeDom.CodeMethodReturnStatement(

            $ctorExpression

        ))

    ) | Out-Null

        

    $builderClass.Members.Add( $realizeMethod ) | Out-Null


 

    # return a hash of the CodeDom objects related to

    # this field

    function field

    {

        param (

            [Type] $type,

            [String] $name

        )

        

        @{

            type = $type

            name = $name

            readonlyFieldDeclaration = $(

# CodeDom doesn't support 'readonly' fields.

# See http://blogs.msdn.com/bclteam/archive/2005/03/16/396915.aspx

#                $field = New-Object System.CodeDom.CodeMemberField($type, $name)

#                $field.Attributes = [System.CodeDom.MemberAttributes]::Public

#                $field

                New-Object System.CodeDom.CodeSnippetTypeMember("`tpublic readonly $type $name;`n")

                )

            fieldDeclaration = $(

                $field = New-Object System.CodeDom.CodeMemberField($type, $name)

                $field.Attributes = [System.CodeDom.MemberAttributes]::Public

                $field

            )

            parameter = New-Object System.CodeDom.CodeParameterDeclarationExpression($type, $name)

            fieldReference = New-Object System.CodeDom.CodeFieldReferenceExpression(

                (New-Object System.CodeDom.CodeThisReferenceExpression),

                $name

            )

            parameterReference = New-Object System.CodeDom.CodeVariableReferenceExpression $name

            setMethodName = "Set$name"

        }                

    }

    

    & $memberScriptBlock | foreach {

        $class.Members.Add( $_.readonlyFieldDeclaration )

        

        $constructor.Parameters.Add( $_.parameter )


 

        $constructor.Statements.Add(

            $(New-Object System.CodeDom.CodeAssignStatement( $_.fieldReference, $_.parameterReference ))

        )

        

        $builderConstructor2.Statements.Add(

            (New-Object System.CodeDom.CodeAssignStatement(

                $_.fieldReference,

                (New-Object System.CodeDom.CodeFieldReferenceExpression(

                    (New-Object System.CodeDom.CodeVariableReferenceExpression "value"),

                    $_.name

                ))

            ))

        )

        

        $builderClass.Members.Add( $_.fieldDeclaration ) | Out-Null

        $setMethod = New-Object System.CodeDom.CodeMemberMethod

        $setMethod.Name = $_.setMethodName


 

        $setMethod.ReturnType = $builderClass.Name

        # This should be Public,Final, but that fails for me. Possible PowerShell bug?

        $setMethod.Attributes = [System.CodeDom.MemberAttributes] "Public"

        $setMethod.Statements.Add(

            (New-Object System.CodeDom.CodeAssignStatement(

                $_.fieldReference,

                (New-Object System.CodeDom.CodeVariableReferenceExpression ("value"))

            ))

        )

        $setMethod.Statements.Add(

            (New-Object System.CodeDom.CodeMethodReturnStatement(

                (New-Object System.CodeDom.CodeThisReferenceExpression)

            ))

        )

        

        $setMethod.Parameters.Add(

            (New-Object System.CodeDom.CodeParameterDeclarationExpression( $_.type, "value" ))

        )

        $builderClass.Members.Add( $setMethod )

        

        $ctorExpression.Parameters.Add( $_.fieldReference )

        

    } | Out-Null    

    

    $csharpCodeProvider = New-Object Microsoft.CSharp.CSharpCodeProvider

    $sw = New-Object System.IO.StringWriter

    $codeGeneratorOptions = New-Object System.CodeDom.Compiler.CodeGeneratorOptions

    $codeGeneratorOptions.BracingStyle = "C"

    $codeGeneratorOptions.BlankLinesBetweenMembers = $false

    

    $csharpCodeProvider.GenerateCodeFromType( $class, $sw, $codeGeneratorOptions )

    

    $sw.ToString()

}

PowerShell DSLs: Using hashtables and scriptblocks together

Previously I presented the use of hashtables and scriptblocks as DSL input formats. You can also convert between them, with processing in between. I tried that out, and I think the result is interesting enough to post. Again, here is the input:

class MyClass {

    field ([string]) S

}

The previous code would use the 'field' function to manipulate the class object as appropriate:

    function field

    {

        param (

            [Type] $type,

            [String] $name

        )

        

        # add the field declaration

        $field = New-Object System.CodeDom.CodeMemberField($type, $name)

        $field.Attributes = [System.CodeDom.MemberAttributes]::Public

        $class.Members.Add( $field )

        

        # add the ctor parameter

        $ctorParameter = New-Object System.CodeDom.CodeParameterDeclarationExpression($type, $name)

        $constructor.Parameters.Add($ctorParameter)


 

        # add the ctor initializer

        $fieldReference = New-Object System.CodeDom.CodeFieldReferenceExpression(

            (New-Object System.CodeDom.CodeThisReferenceExpression),

            $name

        )

        

        $ctorInitializer = New-Object System.CodeDom.CodeAssignStatement(

            $fieldReference,

            (New-Object System.CodeDom.CodeVariableReferenceExpression $name)

        )

        

        $constructor.Statements.Add( $ctorInitializer )

    }

    

    & $memberScriptBlock | Out-Null


 

But another idea is to have the 'field' function produce a collection of CodeDom objects that can be assembled later.

    # return a hash of the CodeDom objects related to

    # this field

    function field

    {

        param (

            [Type] $type,

            [String] $name

        )

        

        @{

            fieldDeclaration = $(

                $field = New-Object System.CodeDom.CodeMemberField($type, $name)

                $field.Attributes = [System.CodeDom.MemberAttributes]::Public

                $field

                )

            parameter = New-Object System.CodeDom.CodeParameterDeclarationExpression($type, $name)

            fieldReference = New-Object System.CodeDom.CodeFieldReferenceExpression(

                (New-Object System.CodeDom.CodeThisReferenceExpression),

                $name

            )

            parameterReference = New-Object System.CodeDom.CodeVariableReferenceExpression $name

        }                

    }

    

    & $memberScriptBlock | foreach {

        $class.Members.Add( $_.fieldDeclaration )

        

        $constructor.Parameters.Add( $_.parameter )


 

        $constructor.Statements.Add(

            $(New-Object System.CodeDom.CodeAssignStatement( $_.fieldReference, $_.parameterReference ))

        )

    } | Out-Null

I suspect that the latter model is a little better because it separates concerns. Consider if I were to add other statements to my language, such as 'property'. The 'foreach' at the end could probably be written in a way that works for both fields and properties. However, the hashtable is slightly concerning, because it's not typed – if I get the key names wrong somewhere, I'm screwed.

I find that I'm spending quite a lot of time on this, but it's important that I find a way to create DSLs quickly. I figured that right now I'm just learning the techniques, and then if I master them, then I can do it more quickly when the time comes.

Friday, November 23, 2007

Immutable data class generator: Skeleton implementation

I've made a little progress on my PowerShell DSL for data classes, and figured it's a good time to show it off.

Here's the input format at this point:

class MyClass {

field ([string]) S

}

(I'm using the ScriptBlock approach.) I generally like the syntax, except for the need to add parentheses around the type. The alternative is to use a fully-qualified string:

class MyClass {

field System.String S

}

I'm not sure which is better, but I'm going with the first one for now, because it allows a more specific type than string.

The basis of the implementation is to write methods named 'class' and 'field'. 'class' is simple; here's an excerpt of the important bits:

$class = New-Object System.CodeDom.CodeTypeDeclaration $name

$class.TypeAttributes = [System.Reflection.TypeAttributes]::NotPublic

$class.IsPartial = $true

$constructor = New-Object System.CodeDom.CodeConstructor

$class.Members.Add( $constructor ) Out-Null

$class

The implementation of 'field' could go in several different ways. For now, I've written it to manipulate the class as appropriate, e.g.:

$field = New-Object System.CodeDom.CodeMemberField($type, $name)

$class.Members.Add( $field )


$ctorParameter = New-Object System.CodeDom.CodeParameterDeclarationExpression($type, $name)

$constructor.Parameters.Add($ctorParameter)


$fieldReference = New-Object System.CodeDom.CodeFieldReferenceExpression(

(New-Object System.CodeDom.CodeThisReferenceExpression),

$name

)


$ctorInitializer = New-Object System.CodeDom.CodeAssignStatement(

$fieldReference,

(New-Object System.CodeDom.CodeVariableReferenceExpression $name)

)


$constructor.Statements.Add( $ctorInitializer )


(I'd like to attach the full script, but I don't see a way to do that in blogspot). It generates this output:

internal partial class MyClass

{

public string S;

private MyClass(string S)

{

this.S = S;

}

}



EDIT: See PowerShell DSLs: Using hashtables and scriptblocks together for a different view of this code.

Immutable data class generator

I'm working on a DSL implementation for defining "data classes" with certain properties in C# (see http://blogs.gotdotnet.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx for an example of the output).

Table of Contents

  1. Goals
  2. Skeleton implementation
  3. ???

PowerShell DSLs: Script block input

As an alternative to using a hashtable for input, you can use a script block. Here's a script-block-way of doing the same thing as before:

class MyClass -accessibilty:public {

member string S

}


and here's one of many ways of handling it

function class {

param (

[String] $name = $( throw
"name is required" ),

[String] $accessibilty,

[ScriptBlock] $memberScriptBlock = $( throw
"member script block is require" )

)


" $accessibilty class $name {"


& $memberScriptBlock % { " public $($_.declaration)" }


" }"

}


function member {

param (

[String] $type = $( throw
"type is required" ),

[String] $name = $( throw
"name is required" )

)


@{

declaration = "$type $name;"


}

}


What's happening here is that the first word on any line becomes a function, and the remaining words are parameters to that function. So, you're now creating an "internal DSL" in PowerShell. This lets you work in a more idoimatic PowerShell manner.


PowerShell DSLs: Hash table input

lassOne way to take PowerShell DSL input is in the form of a hash table. Taking from the Data Type with Builder example, you could write input as:

@{
kind = 'class'
name = 'MyClass'
accessibilty = 'public'
members = @{
type = 'string'
name = 'S'
}
}


How do you consume this input? Here's an example. (Note that the code generation side is not the focal point here -- the way that we interpet the input is what matters.)


if ($input.kind = 'class') {
" $($input.accessibilty) class $($input.name) {"

$input.members | foreach {
" public $($_.type) $($_.name);"
}

" }"

}


Which generates this output:


public class MyClass {
public System.String S;
}


This approach seems most effective when you need to express a lot of attributes on a single element. The downside is that the input seems a bit verbose and unnatural in some cases.

PowerShell DSLs

I've written before about my attraction to Domain-Specific Languages and my curiosity about using PowerShell to handle them, but I only recently got any time to think about it more. I'm working on a DSL implementation for defining "data classes" with certain properties in C# (see http://blogs.gotdotnet.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx#comments for an example).

I have only 3 examples of PowerShell DSLs to work from, and I don't see any guidance in this area, so I figured I'd write about what I find.

Table of Contents

  1. Prior art
  2. Why PowerShell?
  3. Custom invocation w/ a library
  4. DSL tool invocation
  5. Hash table input
  6. Script block input
  7. Using hashtables and scriptblocks together

Warning: technical content ahead

While working at Microsoft, I had a blog for work-related issues at blogs.msdn.com. Now I need a new place to write these things, so this blog will now include technical content, along with the food, politics, family, etc. that have come before.

Friday, November 09, 2007

Reid's Journal Entry: Making Apple Crisp

Today Reid made apple crisp. I wanted to know more about it, so I asked him some questions.

J: How many oranges did you use?
R: Zero oranges. It only takes apples and a few other ingredients, which are kind of like spices. Butter,

J: Oranges?
R: No... I mean, yes

J: What else?
R: Weeds. Then we milk and cereal. This is going to be so funny! Don't write that.

J: After you mixed it up, what did you do?
R: I baked it for 2000 hours. What zee doh.

J: How did it taste?
R: It's not ready for that part yet. We added 2000 drops of stevia in. Time for what it tasted like. It tasted like... stevia. Of course it would.

Friday, October 19, 2007

A new adventure

Today I announced broadly that I'm leaving Microsoft.

I sent 3 emails. Two went to the discussion groups of tools that I own, to announce the change of ownership of these tools. Strictly for business reasons, but then the news started flowing, and I was starting to get questions. So I sent out the third - to basically every person I've worked with in the last 11 years.

What's next?

I'm going to be a stay-at-home dad. The twins are 20 months old. Reid is 6. We want to homeschool Reid, and eventually the twins.

Living off savings will require that we spend a lot less. We currently live 1.9 miles from Microsoft campus, which is a damn expensive place to be. With me not working there, it doesn't make sense to live here, so we're moving away.

We've picked Port Townsend as our new home. It's such a cool city. 8000 people. 25mph speed limits. Hopefully we can bike & walk just about everywhere.

It's also a good choice because I love old, wooden boats, and PT has plenty of them. But that's for the future - right now, our attention will be on the family. Catching up on rest, taking good care of ourselves, being together.

I'm trying to leave Microsoft on good terms, and that includes trying to wrap things up on my current project so that it will succeed when I'm gone.

There's also a lot of work to do to get the house ready, purge our stuff some more, find a new home, pack, and move. Whew!
 
Creative Commons License
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.