Phillip Trelford's Array

POKE 36879,255

Disinherited Types

One of the things that’s always bugged me when using Windows UI libraries like WinForms and WPF is the sheer number of members that pop up in intellisense for a control. The Button type in WPF has around 300 members and a total of 9 levels of inheritance making it hard to find the useful members. Or to put it another way the inherited members occlude the useful members:

Button members

The picture above shows what you actually see in the code completion box in the editor, however for a button you’re probably more interested in the Click event, but that’s several pages away.

Disinherit Type Provider

As a thought experiment I’ve implemented an F# Type Provider that hides type members after a specified level of inheritance:

Disinherited button

In the picture above the members now almost fit in a single page. The last property, not visible here, is an extra property added by the type provider that provides all the hidden members for the instance:

Button instance

 

Type Provider Implementation

Underneath the covers the type provider takes an assembly name as a static parameter and optionally the level of inheritance to expose.

[<Literal>]
let name = @"PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
type WPF = Disinherited< name , level=1 >
let button = WPF.Button()

The provider then reflects over the types in the assembly and creates a proxy type as a provided type and exposes members that are declared within the specified inheritance level.

To provide the member we simply create a corresponding provided member with an expression that evaluates to the underlying type’s member:

    let addMember (def:ProvidedTypeDefinition) ty (mem:MemberInfo) =
        match mem.MemberType with
        | MemberTypes.Constructor ->
            let ci = mem :?> ConstructorInfo
            let c = ProvidedConstructor(toParams ci)
            c.InvokeCode <- fun args -> Expr.Coerce(Expr.NewObject(ci,args), typeof<obj>)
            def.AddMember(c)
        | MemberTypes.Field ->
            let fi = mem :?> FieldInfo
            let field = ProvidedField(mem.Name, fi.FieldType)
            def.AddMember(field)
        | MemberTypes.Property ->
            let pi = mem :?> PropertyInfo
            let prop = ProvidedProperty(mem.Name, pi.PropertyType) 
            prop.GetterCode <- fun args -> Expr.PropertyGet(Expr.Coerce(args.[0],ty), pi)
            def.AddMember(prop)
        | MemberTypes.Event ->
            let ei = mem :?> EventInfo
            let ev = ProvidedEvent(mem.Name, ei.EventHandlerType) 
            ev.AdderCode <- fun args -> Expr.Call(Expr.Coerce(args.Head,ty),ei.GetAddMethod(), args.Tail)
            ev.RemoverCode <- fun args -> Expr.Call(Expr.Coerce(args.Head,ty), ei.GetRemoveMethod(), args.Tail)
            def.AddMember(ev)
        | MemberTypes.Method ->
            let mi = mem :?> MethodInfo
            if not mi.IsSpecialName then
                let m = ProvidedMethod(mi.Name, toParams mi, mi.ReturnType)
                m.InvokeCode <- fun args -> Expr.Call(Expr.Coerce(args.Head,ty), mi, args.Tail)
                def.AddMember(m)
        | _ -> ()

The entire provider is implemented in around 100 lines of code, I’d be interested to hear if anybody else finds it useful :)

Source code

The source is available on GitHub: https://github.com/ptrelford/Disinherit

Calendar Types

Welcome to the 2015 F# Advent Calendar and one of 2 posts for December 3rd. For last year’s advent calendar I tried to follow the seasonal theme and produced an article on generating snowflakes. This year I thought I’d be more literal and look at producing calendar types using F#’s Type Provider mechanism resurrecting a project from 2014, FSharp.Date.

FSharp.Date

FSharp.Date is a simple F# Type Provider, inspired by VB.Net’s date literal feature,that lets you define dates and time values in F# by pressing dot and selecting only valid values:

2015 December 3rd

Further inspired by the advent calendar theme I’ve added a new feature that lets you visualize the calendar month as a tooltip in your editor:

2015 December Calendar

The source is available on BitBucket or you can download the package from Nuget.

But wait there’s more…

On This Day

That got me thinking, what if you could provide topical information on a particular day direct to the editor, and then I found the BBC news site On This Day.

The web site contains a set of both historically significant and quirky stories from the same day in the past.

First I needed a way of finding an article and scraping the news items from the page.

Thankfully the BBC pages use a uniform URL taking the month and day making it easy to get a specific page:

let getPage (month,day) =
    let date = System.DateTime(2005,month,day)    
    let monthName = date.ToString("MMMM").ToLower()
    let url = sprintf "http://news.bbc.co.uk/onthisday/low/dates/stories/%s/%d/default.stm"
                 monthName date.Day
    use client = new System.Net.WebClient()
    client.DownloadString(url)  

The page’s HTML is not well formed so I resorted to a regular expression to parse the news items:

let getNewsItems html =
    let pattern = """<a href="([^"]*)"><span class="h1">(.*?)</span></a><br>(.*?)<br clear="ALL">"""
    let matches = Regex.Matches(html, pattern, RegexOptions.Singleline)
    let newsItems = [for m in matches -> [for i in 1..m.Groups.Count-1 -> m.Groups.[i].Value]]
    [for newsItem in newsItems do
        match newsItem with
        | [link;title;description] ->
            yield "http://news.bbc.co.uk" + link, title.Trim(), description.Trim().Replace("\n","").Replace("\r","")
        | _ -> ()
    ]

Which returns a list of news items for the specified month and day:

> (12,3)|> getPage |> getNewsItems;;
val it : (string * string * string) list =
  [("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2698000/2698709.stm",
    "1984: Hundreds die in Bhopal chemical accident",
    "A dense cloud of lethal gas escapes from a chemical factory in the central Indian city of Bhopal, killing hundreds of people.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2519000/2519715.stm",
    "1992: Bomb explosions in Manchester",
    "Emergency services are dealing with casualties at the scene of two bomb blasts in the centre of Manchester.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_4119000/4119950.stm",
    "1989: Malta summit ends Cold War",
    "The leaders of the two world superpowers declare an end to the Cold War after two days of storm-lashed talks at the Malta summit.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_4119000/4119070.stm",
    "1965: White jury convicts Ku Klux Klansmen",
    "For the first time an all-white jury convicts members of the KKK over the murder of a white civil rights activist Viola Liuzzo.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2519000/2519133.stm",
    "1971: Pakistan intensifies air raids on India",
    "India declares a state of emergency as  airports are hit during a Pakistani attack on the country.");
   ("http://news.bbc.co.uk/onthisday/low/dates/stories/december/3/newsid_2519000/2519451.stm",
    "1988: Egg industry fury over salmonella claim",
    "Claims by a health minister that eggs contain salmonella are branded alarmist and incorrect.")]
> 

Now to create a type provider.

Creating your own Type Provider

If you’re new to writing your own type provider I’d recommend starting with Michael Newton’s Type Providers From the Ground Up post.

First off we need to reference two F# files from the FSharp.TypeProviders.StarterPack.

Paket

Rather than make a static copy I used Paket, a handy .Net dependency management tool, to reference the files directly from GitHub.

This required a simple paket.dependencies file:

source https://nuget.org/api/v2

github fsprojects/FSharp.TypeProviders.StarterPack src/ProvidedTypes.fsi 
github fsprojects/FSharp.TypeProviders.StarterPack src/ProvidedTypes.fs 

and a paket.references file:

File:ProvidedTypes.fsi
File:ProvidedTypes.fs

With that in place all that’s left to do is run > paket install.

Defining the Type Provider

To create a type provider you need a type with the TypeProvider attribute that inherits from TypeProviderFromNamespaces. For this example I only need a single type OnThisDay which provides the news items via a set of static properties:

[<TypeProvider>]
type OnThisDayProvider (config:TypeProviderConfig) as this = 
   inherit TypeProviderForNamespaces ()

   let getProperties newsItems =
       [for (url, title, description) in newsItems ->
           let property = 
               ProvidedProperty(title, typeof<string>, IsStatic=true,
                  GetterCode=fun _ -> <@@ url @@>)
           property.AddXmlDoc(description)
           property]

   let ns = "FsAdvent"
   let asm = System.Reflection.Assembly.GetExecutingAssembly()
   let today = System.DateTime.Now
   let providedType = ProvidedTypeDefinition(asm, ns, "OnThisDay", Some typeof<obj>)
   do  providedType.AddXmlDoc(today.ToLongDateString())
   do  providedType.AddMembersDelayed(fun () ->             
            (today.Month,today.Day) |> getPage |> getNewsItems |> getProperties
       )
   do  this.AddNamespace(ns, [providedType])

Once it’s built you can reference the type provider and get a list of topical news items for the day directly in your editor:

Tunnel

The selected property returns the URL as the value, which you can easily launch with your default browser using Process.Start:

OnThisDay.``1995: Rogue trader jailed for six years``
|> System.Diagnostics.Process.Start

If you fancy a play the source code is available on GitHub: https://github.com/ptrelford/OnThisDay

Happy holidays!

Pimping BASIC with lower casing & JSON literals

Back on April Fool’s day Anthony Green published a funny article “How ‘Roslyn# Finally Unshackled Visual Basic From The Tyranny of the Pretty-Lister”, showing VB.Net with lower case keywords, and how it made it look cooler. And more recently Mads Torgersen gave an “Early View of C# 7” demonstrating pattern matching, a feature that didn’t make it into C# 6, and syntax for tuples.

Taking some inspiration from this I thought I’d add some new extensions to my own language project, Fun Basic (try it free on the Windows Store). But Fun Basic already supports lower case keywords and tuples with pattern matching (which I implemented about 2 years ago), so instead over the last week I’ve added some different language features including cleaner aesthetics for BASIC and JSON literal support.

Hipster BASIC

People often complain about the verbosity of VB.Net, I see two parts to this:

  • End statements – End If, End While, End Select, etc.
  • Casing – Dim is the same length as var, but var just looks smaller

Fun Basic now lets you write `end` and it will infer the type of end for you:

 while i < 10
    i = i - 1
 end

With the lower case keywords & simple end statement you could easily mistake this syntax for Ruby code.

JSON literals

VB.Net has XML literal support, which was a cool feature at the time, but these days XML is more associated with big enterprise, and all the hipsters are using JSON. With that in mind I’ve added JSON literal support to Fun BASIC:

name = "Phil"
age = 27
phil = {"name":name, "age":age}

This allows you to build up strings to send to web based services.

The syntax is also quite close to record syntax in ML, OCaml, F#, TypeScript etc.

Pattern matching

JSON literals are cool, but most of the time you’re using it the other way around, and consuming JSON from an API. For this I’ve added pattern matching over JSON literals.

For example say we want to get the temperature and humidity in London, we can use the Open Weather API, which spits back:

{"coord":{"lon":-0.13,"lat":51.51},
 "weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}],
 "base":"cmc stations",
 "main":{"temp":282.515,"pressure":1026.96,"humidity":97,"temp_min":282.515,"temp_max":282.515,
         "sea_level":1037.24,"grnd_level":1026.96},
 "wind":{"speed":5.75,"deg":228.012},"rain":{"3h":0.6475},"clouds":{"all":92},"dt":1447504501,
         "sys":{"message":0.003,"country":"GB","sunrise":1447485423,"sunset":1447517536},
 "id":2643743,
 "name":"London",
 "cod":200}

With the new Fun Basic pattern matching syntax we can easily extract the values of temp and humidity:

london = "http://api.openweathermap.org/data/2.5/weather?q=London,uk&appid=2de143494c0b295cca9337e1e96b00e0"
weather = Web.Get(london)
{"main":{"temp":temp, "humidity":humidity}} = weather

We can also use the pattern matching in a select case statement:

function ageGroup(person)
  select case person
    case { "age": Is >= 18 }
       return "Adult"
    case else
       return "Child"
  end       
end

sean = {"name":"sean", "age":9}
TextWindow.WriteLine(ageGroup(sean))

Summary

Both features were easy to implement (JSON literals took me the morning), and feel quite natural in the setting of BASIC, you can try them out now in Fun Basic, who knows one day we might see them in mainstream enterprise languages Smile