Supper: Porting my Comfort Zone

It was late, I was bored, this was the result… I think it’s equivalent to its C# counterpart. I’ve modified some lines for illustrative purposes and swallowed a line break here and there for brevity. A few lines at a time:

namespace Banshee.Template
open Banshee.ServiceStack
open Banshee.Sources
open Hyena
open Hyena.Data
open Mono.Addins

Nothing new here, just declaring a namespace and using some others. Dot notation is identical. I was unable to find an equivalent for C# and Java’s static import system but there appears to be a reason.

module Constants =
    let SORT = 190
    let NAME = "Banshee.Template"

No let expressions or values in a namespace so they’re wrapped in a module. Modules get compiled to classes with static values. I’m guessing this is for compatibility with other IL languages. For what it’s worth, I’ve always wondered why you can’t declare constants in a C++ namespace.

type Source() as this = 
    inherit Banshee.Sources.Source (AddinManager.CurrentLocalizer.GetString (Constants.NAME),
                                    AddinManager.CurrentLocalizer.GetString (Constants.NAME),
    let name = Constants.NAME + ".Source"
        this.Properties.SetStringList ("Icon.Name", "multimedia-player")
        Log.DebugFormat ("Instantiating {0}", name)

This (can’t resist a pun…) is interesting, the line after do caused me some time of confusion, apparently this was not defined until the addition of the self-identifier (“as this”) before the body of the type.

The do and let statements are also of interest.

In C#, these would be member variables, in F# they are immutable by default but can be declared otherwise.
Roughly equivalent to the default constructor.

Last, we can see the familiar addition operator overloaded for string concatenation. F# also allows use of the caret, `^’ in this capacity.

type Service(name: string) as self =
    do Log.DebugFormat ("Instantiating {0}", name)
    interface IExtensionService with
        member x.Dispose () = ()
        member x.ServiceName = name
        member x.Initialize () = Log.DebugFormat ("Initializing {0}", (self :> IExtensionService).ServiceName)
    new() = new Service (Constants.NAME + ".Service")

This one’s a bit more juicy; we can see some of the power of functional programming here in the form of the name value, no need to store it anywhere. Especially useful is the enforcement of constructor chaining, since you only really have one, chaining is the only option. The language also allows specialized constructors to have specific continuations, more information here.

Casting syntax is slightly different, shown in the Initialize interface member override, I quite like this style, it’s very easy to read. It’s possibly not surprising, considering the nature of the language, interface methods must be accessed explicitly.

Notes and Other Thoughts

Order is important; inherit, let, do, interfaces, members. The syntax has a few optional elements, for example class and end markers which can, no doubt, be used for hinting when necessary. Coupled with the already terse syntax F# makes for an interesting hybrid, it feels like scripting until you make a mistake, which is when the type system steps in.

Porting something you already know is great for building momentum in a new language. After this, poking bluez via DBus becomes the next step.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s