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

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

Which compiles into

  [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;
      }
    }
  }

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

2 comments

  1. Pingback: F# Weekly #33 2013 | Sergey Tihon's Blog

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>