Phillip Trelford's Array

POKE 36879,255

Software Architect 2009 Conference

For the last 2 days I’ve been attending the Software Architect 2009 conference located at the iconic Royal College of Physicians building opposite Regent's Park in central London. Overall the events have been interesting, that said, the content has not in general been particularly new or ground breaking, but that is probably the nature of the discipline. It has however been good to be reminded of key principles, to listen to the views of others, and as always I’ve found it quite thought provoking. For each talk I attended I’ve created an entry on Twitter @ptrelford:

Tim Ewald on Saving Software Architecture: "When you go too far up, abstraction-wise, you run out of oxygen" Joel on Architecture Astronauts

Kevin Seal on MorganDirect's client-side architecture: Swing app with Eclipse IDE look, blackboard pattern, detailed logs & takes screenshots

Kevlin Henney on Slicing design over time: take time estimate & half it, coding is performance art so practice, test cases are propositions.

Dave Wheeler on Coding a solid UI: "WPF is great", dependency properties are cool, do MVVM pattern, get an HCI expert & use Expression Blend

Richard Blewett on What's New in WF 4.0: Everything. Complete API rewrite. 3.5 favoured code based workflow. 4.0 declarative XAML is king.

Dino Esposito asks "How good are you at .NET software design?" Separation of concerns, OOD principles - prefer composition to inheritance etc

Kevlin Henney on Modelling in the age of agility: Most important aspect of modelling is the -ing, i.e. the social and collaborative aspects.

Simon Brown on "Documenting your software architecture - why and how?" Start with a context and set the scene. Put yourself in others shoes.

Most popular analogy: Construction (Tim Ewald & Kevlin Henney)

Favourite example: Fast-Track Construction of the Empire State Building (Kevlin Henney)

Best term usage: idempotent (Simon Brown)

Best vocabularly usage: pontificate (Kevlin Henney)

Only search term suggestion: Death by UML Fever (Kevlin Henney again)

Finding least common multiples by prime factorization

Least Common Multiple on Wikipedia.

How well can the prime factorization method be expressed in F#? This is my first solution and just for fun:

open System
 
/// Generate sequence of all integer primes
let primes =
    let isPrime x =
        let rec test = function
            | 1 -> true
            | n -> if x % n = 0 then false else test (n-1)
        test (x/2)
    seq {        
        yield! [1;2;3;5;7]
        for n in 11..2..Int32.MaxValue do
            if isPrime n then yield n
        done
    }

/// Compute prime factors
/// <returns>
/// Sequence of prime number powers (x^y) as tuple of (x,y)
/// </returns>
let primefactors x =
    /// Compute prime factor
    let primefactor x =
        primes
        |> Seq.skip 1
        |> Seq.takeWhile (fun prime -> prime <= x)
        |> Seq.tryFind (fun prime -> (x % prime) = 0)
    /// Compute list of prime factors 
    let rec fold acc x =
        match primefactor x with
        | Some factor -> fold (factor::acc) (x/factor)
        | None -> acc
    fold [] x
    |> Seq.countBy (fun x -> x)
    
/// Compute lowest common multiple    
let lcm xs =       
    xs                              // {8;9;21}
    |> Seq.map primefactors         // {{2^3};{3^2};{3^1;7^1}}
    |> Seq.concat                   // {2^3;3^2;3^1;7^1}
    |> Seq.groupBy (fun (x,y) -> x) // {{2;{2^3}};{3;{3^1;3^2}};{7;{7^1}}}
    |> Seq.map (fun (x,xys) ->       
        x,                          // 3
            xys                     // {3^1;3^2}
            |> Seq.map snd          // {1;2}
            |> Seq.max              // 2
    )                               // {2^3;3^2;7^1}
    |> Seq.map (fun (x,y) ->
        pown x y                    // {8;9;7}
    )
    |> Seq.reduce (*)               // 504

do  lcm [8;9;21] |> printf "%d"     // yields 504

C# Scripting

The .Net Framework ships with a C# code compiler that lets you generate in-memory assemblies. This can be used to run C# scripts without the need for the installation of a large application like PowerShell. The following code, which targets .Net 2.0, builds into a 7K executable, and is all that is needed to run C# source files from the command line:

using System;
using System.CodeDom.Compiler;
using System.Collections.Specialized;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.CSharp;
using System.Collections.Generic;

static class Program
{
    /// <summary>
    /// Executes specified C# script file
    /// </summary>
    /// <param name="args">Path of C# script file</param>
    static void Main(string[] args)
    {
        // Check parameters
        if (args.Length == 0)
        {
            Console.WriteLine("Please specify a C# script file");
            Environment.Exit(-1);
        }
        // First parameter is source file path
        string path = args[0];
        // Check file exists 
        if (!File.Exists(path))
        {            
            Console.WriteLine("Specified file does not exist");            
            Environment.Exit(-1); 
        }
        // Read source from file
        string source = ReadFile(path);
        // Initialize compiler options
        CompilerParameters compilerParameters = 
            new CompilerParameters();      
        compilerParameters.GenerateExecutable = true;
        compilerParameters.GenerateInMemory = true;
        compilerParameters.TreatWarningsAsErrors = true;
        compilerParameters.CompilerOptions = "/nowarn:1633"; // unrecognized pragmas
        // Prepass source for #pragma reference statements        
        StringReader reader = new StringReader(source);       
        while (true)
        {
            string line = reader.ReadLine();
            if (line == null) break;            
            string pattern = 
                "\\s*#pragma\\s+reference\\s+\"(?<path>[^\"]*)\"\\s*";
            Match match = Regex.Match(line, pattern);                   
            if (match.Success)            
                compilerParameters.ReferencedAssemblies.Add
                    (match.Groups["path"].Value);            
        }
        // Specify .NET version
        Dictionary<string, string> providerOptions =
            new Dictionary<string, string>();
        providerOptions.Add("CompilerVersion", "v3.5");
        CSharpCodeProvider provider = new CSharpCodeProvider(providerOptions); 
        // Compile source           
        CompilerResults results =
                provider.CompileAssemblyFromSource(
                    compilerParameters,
                    new string[] { source });
        // Show errors
        if (results.Errors.HasErrors)
        {
            Console.WriteLine("Errors Building " + path);
            foreach (var err in results.Errors)
                Console.WriteLine(err);
            Environment.Exit(-1);
        }
        // Extract argument tail
        string[] parameters = new string[args.Length - 1];
        Array.Copy(args, 1, parameters, 0, args.Length-1);
        // Invoke compiled assembly's entry point
        results.CompiledAssembly.EntryPoint.Invoke
            (null, new object[1] { parameters });        
    }
    
    private static string ReadFile(string path)
    {
        using (StreamReader reader = File.OpenText(path))
            return reader.ReadToEnd();
    }
}

 

Script files look just like Console applications:

using System;

public class Class1
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello World");
    }
}

 

Finally additional assemblies can be referenced using #pragma directives:

#pragma warning disable 1633 // disable unrecognized pragma directive warning
#pragma reference "System.Windows.Forms.dll"

using System.Windows.Forms;

public class Class1
{
    static void Main(string[] args)
    {
        MessageBox.Show("Hello World");
    }
}