F# class getter fun
I was playing with Neo4J (following a recent post I stumbled upon by Sergey Tihon), and had everything wired up and ready to test out, but when I tried running my code I kept getting errors saying that I hadn’t connected to the neo4j database. This puzzled me because I had clearly called connect, but every time I tried to access my connection object I got an error.
The issue was that I didn’t realize that f# class members are always deferred. It makes sense that they are after I traced through it, but I couldn’t spot the bug for the life of me at first.
My code looked like this:
module Connection =
type Connection (dbUrl) =
member x.client = new GraphClient(new Uri(dbUrl))
member x.create item = x.client.Create item
member x.connect() =
x.client.Connect()
x
If I had more experience with F# I probably would have spotted this right away, but it took me a while to figure out what was going on. The issue here is
[fsharp highlight=”4”]
module Connection =
type Connection (dbUrl) =
member x.client = new GraphClient(new Uri(dbUrl))
member x.create item = x.client.Create item
member x.connect() =
x.client.Connect()
x
[/fsharp]
Which compiles into
[csharp highlight=”15”]
[AutoOpen]
[CompilationMapping(SourceConstructFlags.Module)]
public static class Connection
{
[CompilationMapping(SourceConstructFlags.ObjectType)]
[Serializable]
public class Connection
{
internal string dbUrl;
public GraphClient client
{
get
{
return new GraphClient(new Uri(this.dbUrl));
}
}
public Connection(string dbUrl)
{
Connection.Connection connection = this;
this.dbUrl = dbUrl;
}
public NodeReference<a> create<a>(a item) where a : class
{
return GraphClientExtensions.Create<a>((IGraphClient) this.client, item, new IRelationshipAllowingParticipantNode<a>[0]);
}
public Connection.Connection connect()
{
this.client.Connect();
return this;
}
}
}
[/csharp]
Clear as day now. Each time you call the property it returns a new instance. I had assumed that since the member wasn’t a function that it would be a property, not an auto wrapped getter.
The fix was easy:
module Connection =
type Connection (dbUrl) =
let graphConnection = new GraphClient(new Uri(dbUrl))
member x.client = graphConnection
member x.create item = x.client.Create item
member x.connect() =
x.client.Connect()
x
Which now generates
[AutoOpen]
[CompilationMapping(SourceConstructFlags.Module)]
public static class Connection
{
[CompilationMapping(SourceConstructFlags.ObjectType)]
[Serializable]
public class Connection
{
internal GraphClient graphConnection;
public GraphClient client
{
get
{
return this.graphConnection;
}
}
public Connection(string dbUrl)
{
Connection.Connection connection = this;
this.graphConnection = new GraphClient(new Uri(dbUrl));
}
public NodeReference\<a\> create\<a\>(a item) where a : class
{
return GraphClientExtensions.Create\<a\>((IGraphClient) this.client, item, new IRelationshipAllowingParticipantNode\<a\>[0]);
}
public Connection.Connection connect()
{
this.client.Connect();
return this;
}
}
}
That’s more like it