Phillip Trelford's Array

POKE 36879,255

TickSpec dependency graph

Scott Wlaschin has just posted a really interesting series on Dependency cycles over on the F# for fun and profit site. The last post shows cycles and modularity in the wild comparing open source C# and F# projects including SpecFlow and TickSpec which have almost identical functionality,.

Here’s the dependency diagram for SpecFlow (C#):

 specFlow

and for TickSpec (F#):

tickSpec

They both have very similar functionality and in fact TickSpec implements it’s own parser too. Read Scott’s article to better understand why such large differences exist between C# and F# projects.

F# Deep Dives

You’ve read the introduction books, you’ve keyed in the hello world examples, now it’s time to dive deep into solutions from experienced developers working in interesting domains.

Deep Dive

Like many of you I’m sure I’ve collected a bookcase full of books introducing an array of languages and technologies. But like you I crave material that is based on actual experience of developing real-world systems in interesting domains. The excellent Beautiful Architecture and Beautiful Code books present chapters from experienced developers who talk about real-world applications they’ve worked on. F# Deep Dives goes deep on simple functional solutions with F# applied to interesting domains like finance, machine learning and games.

F#

F# is a practical, functional-first language that lets you write simple code to solve complex problems. By focusing on F# we have been able to draw from a wealth of experienced developers working on practical problems in interesting domains. F# is also a very expressive language which means that each chapter can focus on showing solutions without having to sacrifice content because of excessive amounts of boilerplate. The solutions should be easy to follow for developers with or without F# experience and interesting whether you intend to solve problems with F# or another functional-first language like Scala or Clojure.

Deal of the day

If all that sounds interesting I think you’ll enjoy F# Deep Dives:

petricek2_cover150 

Work on the book started in December 2012, it’s currently in MEAP with Manning and today (17th May 2013) F# Deep Dives is Manning’s deal of the day - use code: dotd0517au

Fixed Width Data Files

Scanning over Alvin Ashcraft’s excellent Morning Dew (a must read for .Net devs as is Chris Alcock’s Morning Brew), I came across a short article from Richard Carr on writing Fixed Width Data Files using C#.

Richard creates a class that inherits from StreamWriter, and all-in it’s just over 50 lines of idiomatic C# code:

using System;
using System.IO;
using System.Text;

public class FixedWidthWriter : StreamWriter
{
    public int[] Widths { get; set; }

    public char NonDataCharacter { get; set; }

    public FixedWidthWriter(
          int[] widths, string path, bool append, Encoding encoding)
        : base(path, append, encoding)
    {
        NonDataCharacter = ' ';
        Widths = widths;
    }

    public FixedWidthWriter(int[] widths, string file)
        : this(widths, file, false, Encoding.UTF8) { }

    public FixedWidthWriter(int[] widths, string file, bool append)
        : this(widths, file, append, Encoding.UTF8) { }

    public void WriteLine(string[] data)
    {
        if (data.Length > Widths.Length)
            throw new 
                InvalidOperationException("The data has too many elements.");

        for (int i = 0; i < data.Length; i++)
        {
            WriteField(data[i], Widths[i]);
        }
        WriteLine();
    }

    private void WriteField(string datum, int width)
    {
        char[] characters = datum.ToCharArray();
        if (characters.Length > width)
        {
            Write(characters, 0, width);
        }
        else
        {
            Write(characters);
            Write(new string(NonDataCharacter, width - characters.Length));
        }
    }
}

As you’d probably guess the same functionality takes half the lines to express in F#:

open System
open System.IO
open System.Text

type FixedWidthWriter(widths:int[], path:string, append, encoding) =
    inherit StreamWriter(path, append, encoding)
    member val Widths = widths with get, set
    member val NonDataCharacter = ' '  with get, set
    new(widths, file) = 
        new FixedWidthWriter(widths, file, false, Encoding.UTF8)
    new(widths, file, append) =
        new FixedWidthWriter(widths, file, append, Encoding.UTF8)
    member this.WriteLine(data:string[]) =
        if data.Length > this.Widths.Length
        then invalidOp "The data has too many elements."
        for i = 0 to data.Length-1 do      
            this.WriteField(data.[i], this.Widths.[i])
        base.WriteLine()
    member private this.WriteField(datum:string, width) =
        let xs = datum.ToCharArray()
        if xs.Length > width
        then base.Write(xs, 0, width)
        else        
            base.Write(xs)
            base.Write(String(this.NonDataCharacter, width - xs.Length))

The C# implementation uses classes and inheritance. In F# we’d typically favour composition over inheritance and start with the simplest possible thing that works, which in this case is a function that takes a file path, widths and the lines to write:

let WriteFixedWidth (path:string) (widths:int[]) (lines:string[] seq) =
    let pad = ' '
    use stream = new StreamWriter(path)
    let WriteField (datum:string) width =
        let xs = datum.ToCharArray()
        if xs.Length > width
        then stream.Write(xs, 0, width)
        else        
            stream.Write(xs)
            stream.Write(String(pad, width - xs.Length))
    for line in lines do
        for i = 0 to widths.Length-1 do 
            WriteField line.[i] widths.[i]
        stream.WriteLine()

The function is about half the size again and more closely follows YAGNI. To test it we can simply write:

let widths = [|20; 7; 6|]
[
[|"Company"; "Spend"; "Rating"|]
[|"Quality Foods Limited"; "1000000"; "Gold"|]
[|"The Pieman"; "50000"; "Silver"|]
[|"Bill's Fruit and Veg"; "10000"; "Bronze"|]
]
|> WriteFixedWidth "c:\\test.txt" widths

Does the language you chose make a difference?