0

As a part of rewriting my C# code in F# I have come across the situation where I do not know how to best handle the default values of the System.String type returned from a C# service.

The C# equivalent of what I would like to do would be:

var myCSharpString = CSharpService.GetCSharpString() ?? "";

Simply put, if the string returned by GetCSharpString is null or default(string), I would like it to be set to " " instead.

However, what will happen if I try to do the following statement in F#?

let myFSharpString = CSharpService.GetCSharpString

In the case where GetCSharpString returns null or default(string), will myFSharpString be the default value of strings in F# (that is: " ")? Or will I have to explicitly do a null check, such as:

let myFSharpString =
    match CSharpService.GetCSharpString with
    | val when val = Unchecked.defaultof<System.String> -> ""
    | val -> val

I have found myself to do checks such as this several times, and I simply cannot get over the fact of how much code is needed for such a simple task.

Could someone enlighten me of whether such null checks are actually needed in F# when dealing with C# services that returns System.String?

Update:

I am not asking about the ??-operator in the combination with the F#'s Option type, as has been answered before in this post. Rather I am asking about how to handle the C# null value of strings in an F# context.

Another seemingly possible answer I have tried, would be to make a custom operator, such as:

let inline (|??) (a: 'a Nullable) b = if a.HasValue then a.Value else b

This, however, gives a compile error, since F# interprets the return value of GetCSharpString as of type 'string', which in F# is NotNullable.

Community
  • 1
  • 1
Tormod Haugene
  • 3,538
  • 2
  • 29
  • 47
  • 2
    You can use the match version as an operator – John Palmer Jun 25 '15 at 10:57
  • `let (|??) = function v when v = Unchecked.defaultof -> System.String.Empty | v -> v ` – Petr Jun 25 '15 at 11:58
  • Correcting your custom operator: `let inline (|??) x y = match x with null -> y | _ -> x` – Daniel Jun 25 '15 at 14:05
  • Your question is premised on an incorrect assumption. The default value of strings in F#, as is the default value of all reference types in the .NET environment, is `null`. – phoog Jun 26 '15 at 19:00
  • "F# interprets the return value of GetCSharpString as of type 'string', which in F# is NotNullable." That's not true. In F#, only types defined in F# cannot be null (by default). Reference types defined in other languages can be null. – Marc Sigrist Jun 27 '15 at 09:47
  • "rewriting my C# code in F#..." How did you handle the potential null strings in the original C# code? Either a) you had a lot of null checks already in the C# code, in which case any null checks in the F# code will not cause more overhead than in C#, or b) you did not have to check null strings in C# (because they were harmless in your case), in which case you also do not have to check them in F#. If you clarify these aspects first, then the best approach in F# will follow automatically. – Marc Sigrist Jun 27 '15 at 09:54

1 Answers1

1

Define a function and a single-case active pattern:

let safeStr = function
    | null -> String.Empty
    | x -> x
let (|SafeStr|) = safeStr

You can now use either the function:

let myFSharpString = safeStr <| CSharpService.GetCSharpString()

... or the active pattern:

let processCSharpString (SafeStr x) =
    // x is never null :)
Marc Sigrist
  • 3,964
  • 3
  • 22
  • 23