return a tuple with names in F#

Viewed 1140

In C# I can do this:

public (bool result, string message) Hello()
{
    ...
    return (true, "ok")
}

I am trying to figure out how to do it in F#.

I can do:

let Hello () =
    (true, "ok")

but then, when I call Hello from C#, I have to get the elements as 'Item1' and 'Item2'.

Is there a way to name the field in the returned tuple?

I tried:

let hello () : (result, message ): bool * string =

and a few other variations, but I can't make that work.

The type returned is seen as a tuple object, in C#, whereas the pure C# example shown above doesn't seem to be using the tuple type.

I guess you can't name the items in a tuple object, but is there a way to return parameters like in C#?

3 Answers

Standard F# tuples are System.Tuple under the hood (which would be written as Tuple<bool, string> in C#), while the tuple returned from your C# code is the newer System.ValueTuple. To create that from F#, you need to prefix your tuple creation with the struct keyword. That still doesn't let you name tuple elements in F#, though; that is only a C# compiler feature and has no support in the underlying BCL types.

The options you have in F# to use the individual returned values in a similar manner are

I think you need to use a struct tuple in your F#code, for example

let f (struct (x,y)) = x+y

You can find the design document here

https://github.com/fsharp/fslang-design/blob/master/FSharp-4.1/FS-1006-struct-tuples.md

When you want to interop with C#, you should look at this https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/tuples

In summary, calling a C# code, you can

open TupleInterop

 let struct (newX, newY) = Example.AddOneToXAndY(struct (1, 2))
 // newX is now 2, and newY is now 3

F# doesn't support this feature today, but if you want to expose names for C# you can manually use System.Runtime.CompilerServices.TupleElementNamesAttribute. Note that you need to use struct to get F# to use ValueTuple instead of Tuple, to match C#.

let Hello () : 
    [<return: TupleElementNames([| "result"; "message" |])>] struct(bool * string) =
    (true, "ok")
Related