Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

The F# equivalent of C#'s 'out'

Tags:

I am rewriting a C# library to F# and I need to translate the following code

bool success;
instance.GetValue(0x10, out success);

what is the equivalent of the out keyword in F#?

like image 798
kasperhj Avatar asked Feb 24 '15 08:02

kasperhj


People also ask

Will there be end of the world season 3?

Creator Charlie Covell said in an exclusive interview with Radio Times that there are no plans for a third installment.

What did Alyssa and James leave at the house?

Plot. After unsuccessfully trying to move Koch's body out of the bedroom, James and Alyssa meticulously clean the house to remove evidence of their stay. James shows Alyssa the Polaroids and footage proving that Koch might have hurt her, and they resolve to leave the evidence by his body.

How old is Alyssa and James season 2?

James is 17 and is pretty sure he is a psychopath. Alyssa, also 17, is the cool and moody new girl at school. The pair make a connection and she persuades him to embark on a road trip in search of her real father.

Is the end of the f world a true story?

But even though this series isn't based on any real events, the emotional core of the show is based in the very real experience of being a teenager who is totally confused about life, and still trying to figure themselves out.


Video Answer


2 Answers

Neither wasatz's answer nor Max Malook's is complete. There are three ways of calling methods with out parameters. The second and third ways also work with ref parameters.

For the examples, assume the following type:

open System.Runtime.InteropServices //for OutAttribute
type SomeType() =
    member this.GetValue (key, [<Out>] success : bool byref) =
        if key = 10 then
            success <- true
            "Ten"
        else
            success <- false
            null

Assume also that we have an instance of that type:

let o = SomeType()

Option 1

You can let the F# compiler handle the out parameter by tupling it with the return value:

let result1, success1 = o.GetValue 10
let result2, success2 = o.GetValue 11

Running the above lines in F# interactive yields

val success1 : bool = true
val result1 : string = "Ten"
val success2 : bool = false
val result2 : string = null

Option 2

You can use a mutable value, passing its address with the & operator:

let mutable success3 = false
let result3 = o.GetValue (10, &success3)
let mutable success4 = false
let result4 = o.GetValue (11, &success4)

In F# interactive, the result is

val mutable success3 : bool = true
val result3 : string = "Ten"
val mutable success4 : bool = false
val result4 : string = null

This option is best when you are delegating to another method, since you can pass the calling method's out parameter directly to the called method. For example, if you are implementing a wrapper around IDictionary<_,_>, you can code the TryGetValue method as

//...
interface IDictionary<'TKey, 'TValue> with
    member this.TryGetValue (key, value) = inner.TryGetValue (key, &value)
    //...

Option 3

You can use a reference cell:

let success5 = ref false
let result5 = o.GetValue (10, success5)
let success6 = ref false
let result6 = o.GetValue (11, success6)

The output:

val success5 : bool ref = {contents = true;}
val result5 : string = "Ten"
val success6 : bool ref = {contents = false;}
val result6 : string = null

Warning!

Be careful not to use the ref keyword as you would in C# for an in/out parameter. For example, the following does not yield the desired result:

let success7 = false
let result7 = o.GetValue (10, ref success7)

The output:

val success7 : bool = false
val result7 : string = "Ten"

Why does success7 hold the value false? Because success7 is an immutable variable.

In C#, ref calls attention to the fact that you are passing a reference to a variable as the argument for a ref parameter. It simply serves as insurance that the programmer of the caller is aware that the variable may be modified by the called method. In F# however, ref creates a new reference cell holding a copy of the value of the following expression.

In this case, we are making a reference cell that holds the value copied from the success7 variable, but not assigning that new reference cell to any variable. We then pass that reference cell to the GetValue method, which modifies the content of the reference cell. Because the calling method has no variable pointing to the modified cell, it has no way of reading the new value of the reference cell.

like image 71
phoog Avatar answered Sep 28 '22 02:09

phoog


You should probably return an option or a tuple instead. Because F# has pattern matching you really don't need out parameters since there are better ways to return more than one value from a function.

So, something like this would be more idiomatic

let (value, success) = instance.GetValue(0x10)

where instance.GetValue is a

unit -> ('a, bool) 

Or you could return an option and do something like

match instance.GetValue(0x10) with
| Some value -> doStuff value
| None -> failwith "Oops!"
like image 31
wasatz Avatar answered Sep 28 '22 01:09

wasatz