Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a simpler way to use interfaces in F# implicitly?

Tags:

interface

f#

I am playing a bit with F# interfaces, by creating a simple data access class.

The interface is:

type IUserAccess =
    abstract member GetUsers : (dbSchema.ServiceTypes.Users -> bool) -> dbSchema.ServiceTypes.Users seq 
    abstract member GetAllUsers : unit -> dbSchema.ServiceTypes.Users seq 

In the class, I am calling the methods in this way:

type UserAccess() = 
    let db = dbSchema.GetDataContext()
    interface IUserAccess with
        member this.GetUsers cond  =
            let query = query {
                for row in db.Users do
                select row } 
            query |> Seq.where cond

        member this.GetAllUsers () =
            (this:>IUserAccess).GetUsers (fun _ -> true)

What I'm a bit concerned with is the way I am calling GetAllUsers function, specifically with part (this:>IUserAccess). What is the simplest way of calling methods that are implemented within the same interface?

One simple option I can think of is creating GetUsers method directly within UserAccess() class and then calling it from the interface implementation of both GetUsers and GetAllUsers, but that means a new private method implemented, which I would like to avoid. Is there another option?

like image 716
Tomas Pastircak Avatar asked Apr 27 '14 15:04

Tomas Pastircak


2 Answers

I think the solution by @vcsjones is probably the best option if you want to avoid defining a separate method directly inside the class. That said, declaring a separate method is actually not that ugly. You can use local definition using let binding (which is automatically compiled as a private method) and I think it makes the code look quite nice:

type UserAccess() = 
    let db = dbSchema.GetDataContext()
    let getUsers cond = 
      let query = query {
          for row in db.Users do
          select row } 
      query |> Seq.where cond

    interface IUserAccess with
        member this.GetUsers cond  = getUsers cond
        member this.GetAllUsers () = getUsers (fun _ -> true)

I generally quite like this style, because it separates all the private implementation from the part of the definition where you're defining the public exposed API.

like image 153
Tomas Petricek Avatar answered Oct 06 '22 00:10

Tomas Petricek


F# always implements interfaces explicitly, so your options are pretty much as you stated, but you can avoid redundant casting by introducing a let binding:

type IUserAccess =
    interface
        abstract member GetUsers : (obj -> bool) -> unit
        abstract member GetAllUsers : unit -> unit
    end

type Foo() as self =
    let userAccess = self :> IUserAccess
    interface IUserAccess with
        member this.GetUsers(q : (obj -> bool)) : unit =
           ()
        member this.GetAllUsers() =
            userAccess.GetUsers(fun _ -> true)

I just simplified your interface and object so I could get something compiling real quick.

like image 28
vcsjones Avatar answered Oct 05 '22 23:10

vcsjones