Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to do extensive null checks in F# when calling C# code

I would like to know the best way to interact with C# code from F# in a functional way, when I have to check null many times.

From C#, is easy because I have null operator

public bool Authorize(DashboardContext dashboardContext)
{
    var context = new OwinContext(dashboardContext.GetOwinEnvironment());
    var user = context.Authentication.User;
    return user?.Identity?.IsAuthenticated ?? false;
}

From F#, I made this

let authorize (ctx:DashboardContext) =
    match OwinContext(ctx.GetOwinEnvironment()) with
    | null -> false
    | c -> match c.Authentication.User with
            | null -> false
            | user -> user.Identity.IsAuthenticated

But I am not happy with this. What is the functional way for doing this right? I thought maybe some computation expression would help, but I don't know how to accomplish yet.

like image 792
Francisco Berrocal Avatar asked Jun 12 '17 14:06

Francisco Berrocal


1 Answers

Option.ofObj will convert a nullable object into an Option. Then you can use the helpers already defined in the Option module. For example, part of the pattern that you've written there is already encapsulated by Option.bind.

let authorize (ctx:DashboardContext) =
    ctx.GetOwinEnvironment() |> OwinContext |> Option.ofObj
    |> Option.bind (fun c -> c.Authentication.User |> Option.ofObj)
    |> Option.map  (fun user -> user.Identity.IsAuthenticated)
    |> Option.defaultValue false

Option.bind takes an Option<'a> and a function that takes the type 'a and returns an Option<'a>. When it is used in a pipeline it's a way of "mapping" a Some or filtering it out into a None.

I would say that the function you wrote looks fine actually, but this way might be considered a little bit more idiomatic, though it's arguably also a bit harder to follow in this example. Option.bind really comes into its own when it saves multiple levels of nesting.

It's worth noting that in both your F# function and mine we're assuming non-nullness of the Authentication and Identity properties and risking null reference exceptions when accessing their properties. That's in contrast to the C# method using null propagation. There isn't currently a built-in way to do that in F# but there are probably some advanced methods for simulating it.

It is also possible to do this with computation expressions. See the MaybeBuilder here.

like image 57
TheQuickBrownFox Avatar answered Oct 09 '22 12:10

TheQuickBrownFox