Day 2: Poke and Destroy!

After yesterday’s small success we take a break from the big picture and
focus on harassing bluez into doing some work for us.

open System
open System.Collections.Generic
open DBus

Will I ever remove these lines of pre-amble? Perhaps, but first I’ll try
snipping out any mundane ones if it’s more than say, 5 lines… I think they’re
useful, the reader can be sure he’s not missing anything important if he wants
to run the examples and has these.

[<Literal>]
let IFDEV = "org.bluez.Device1"

This is cool! People who’ve done some C++ template programming will recognise
this as a constexpr. It’s used later, you’ll see. Minor difference in the Attribute style compared with C# vis-á-vis the <> symbols either side of the attribute name.

[<Interface ("org.freedesktop.DBus.Properties")>]
type IProperties =
    abstract member Get : string -> string -> obj 
    abstract member Set : string -> string -> obj -> unit
    abstract member GetAll : string -> IDictionary<string,obj>

The obligatory interface definiton for accessing properties, I’m not really worried about signals at this point. As an aside, why is this interface not built into DBus bindings, it wasn’t when I worked with it in Java either?

I was hoping to get some use out of F#’s built in map types but obviously we’re limited to the intersection of types available in all IL languages when working with dbus-sharp, hence the IDictionary. If you’re wondering, obj is just a type definition equivalent to System.Object.

[<Interface (IFDEV)>]
type IBluetoothDev =
    abstract Disconnect : unit -> unit
    abstract Connect : unit -> unit
    abstract ConnectProfile : string -> unit
    abstract DisconnectProfile : string -> unit
    abstract Pair : unit -> unit
    abstract CancelPairing : unit -> unit
    abstract Address : string with get
    abstract Name : string with get
    // Other Properties ommited for brevity

Spot the Literal?

Yes, I skipped the adapter since it wasn’t interesting and moved straight to the Device API. In yesterday and today’s examples there were a few unit type declarations, the concept is identical to void in other C-family languages.

At this point, we can actually grab a remote object and do some work with it. Unfortunately accessing properties doesn’t work the way I was expecting them to, generating a DBus error stating that we attempted to invoke a method which does not exist.

With some testing, in the form of stripping the MediaPlayer2 interface definition out of Banshee and making a small self contained example, it can be shown that DBus objects exported from IL langauges have accessible properties. I hypothesize that since the exported objects contain methods covered by the property system, that these methods are exported (although they do not appear in introspection data) and grant access to the properties.

The solution is nothing fancy, below is a slightly mangled decorator pattern covering the properties with the correct DBus call. In lieu of the problem being addressed in dbus-sharp, a reflecting proxy (I have only used these indirectly) may save hand-rolling a decorator for each interface that is needed.

type DevProxy (bus: Connection, name: string, obj: ObjectPath) =
    let dev = bus.GetObject<IBluetoothDev>(name, obj)
    let props = bus.GetObject<IProperties>(name, obj)
    interface IBluetoothDev with
        member x.Disconnect () = dev.Disconnect ()
        member x.Connect () = dev.Connect ()
        member x.ConnectProfile y = dev.ConnectProfile y
        member x.DisconnectProfile y = dev.DisconnectProfile y
        member x.Pair () = dev.Pair ()
        member x.CancelPairing () = dev.CancelPairing ()
        member x.Address = (props.Get IFDEV "Address").ToString ()
        member x.Name = (props.Get IFDEV "Name").ToString ()

printfn "Hello, Bluez"

let bus  = Bus.System
let name = "org.bluez"
let mac  = "<Bluetooth MAC Here>"
let path = new ObjectPath ("/org/bluez/hci0/dev_" + mac)
printfn "Requesting Remote Objects"
let dev = DevProxy(bus, name, path) :> IBluetoothDev
let props = bus.GetObject<IProperties>(name, path)
printfn "Got Remote Objects"

try
    printfn "Device: [%s] - %s" dev.Address dev.Name
with
    | ex -> printfn "%s\n%s" ex.Message ex.StackTrace
    
dev.Connect ()
dev.Disconnect ()

printfn "Bluez, Goodbye"

Finally, we grab a handle to the paired device and introduce ourselves by prodding it in a couple of places, like a teenager on IRC. Tomorrow we’ll most likely investigate some bluez interfaces available through the session bus.

Parting Concern

Prototyping like this is great, quickly displaying and importantly testing functionality that will be used in the eventual concrete implementation. But, what of that key word; one difficulty I encountered while working with a similar Java system was that since functionality depended on variables originating from a live system I found it impossible to rigourously test the system, relying on an ad-hoc approach not much different from the example above. Not only did this reduce my confidence, it also stopped me documenting the steps necessary to correct the issues. Comments and advice on how to combat this problem are welcome and appreciated.

Advertisements

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),
                                    Constants.SORT,
                                    "extension-unique-id")
    let name = Constants.NAME + ".Source"
    do 
        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.

let
In C#, these would be member variables, in F# they are immutable by default but can be declared otherwise.
do
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.

Day 1: Setting Up

Summer of Code officially started on the 19th, with an exam the following day and another four days later I did not get much done this week! So, hot on the heels of Understanding Programming Languages yesterday, I decided to configure my environment ready for some development.

Pre-requisites

Gentoo is an empowering distribution, but at times can feel like a self-inflicted disability.

F# bindings for MonoDevelop will make life much easier (I do not fancy writing an fsproj file by hand!). Unfortunately the ebuild is a live one (i.e. direct from Git) and failed to compile on my system. The first hurdle appeared to be applying an assembly redirection from the requested FSharp.Core assembly version 4.3.0 to 4.3.1. Oh dear!

Luckily, the overlay system allows me to easily create my own package for the 4.3.0 assembly, working around the problem, but I still couldn’t get the bindings to compile. After many hours of fiddling, I managed to install them for my user. Not ideal, I’ll need to manage updates myself, but at least I can get started now and have some experience with the F# compiler.

Tentative Steps

With the above done, I could now create a project. BCM (Banshee Community Extensions) is mostly written in C# and provides a script for quickly creating a new extension. Using the script and existing C# template project as a starting point gets us some build infrastructure and an XML file for Mono.Addins which we can easily customize.

At this point, we note that Automake wants to use the C# compiler on our F# files! Redefining the MCS variable (among other things) works as a Quick Hack and highlights some differences between the two compilers. I’m not sure why, but although the option names are the same, F# compiler requires a second hyphen in front of each… <sigh />

A Cautious Hop

Finally, at this point there is some code to show. It’s a tiny example containing no moving parts but is useful for two reasons; first it shows an F# newcomer (me!) some of the syntax for polymorphism and secondly, combined with the prior ground work gets us to the point where we can see an effect on the outside world, i.e. the extension can be loaded by Banshee and we see an (at present) icon-less source appear when it is enabled.

namespace Banshee.Template

type Source() = 
    inherit Banshee.Sources.Source ()

type Service() =
    interface Banshee.ServiceStack.IExtensionService with
        member this.Dispose () = ()
        member this.get_ServiceName () = "TemplateService"
        member this.Initialize () = printfn "Starting TemplateService"

Next Up

The most logical next step would be to tidy up the changes I’ve made to enable F# projects to build, figuring out what changes are needed to get this done via GNU Autotools is definitely a priority. Porting the rest of the C# template extension to F# is also an ideal candidate for attention due to the valuable language experience that I would gain. Once done it would be useful to expand the extension creation script for other users, though that has a low priority. Finally, today’s work provides an excellent place to start prototyping.

A slow day, not many achievements but each one felt significant.