F # equivalent to C # 'out'

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

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

what is equivalent to the out keyword in F #?

+7
f # c # -to-f #
source share
4 answers

Neither Vazat's answer nor Max Maluk is finished. There are three ways to call methods with out parameters. The second and third methods also work with ref parameters.

For examples, suppose 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 

Suppose also that we have an instance of this type:

 let o = SomeType() 

Option 1

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

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

Running the above lines interactively F #

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

Option 2

You can use a mutable value by passing its address to 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

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

This option is best when delegating to another method, because you can pass the parameter of the method call directly to the called method. For example, if you use a wrapper around IDictionary<_,_> , you can encode the TryGetValue method as

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

Option 3

You can use the reference cell:

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

Exit:

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

Attention!

Be careful not to use the ref keyword, as in C # for an I / O parameter. For example, the following does not produce the desired result:

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

Exit:

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

Why success7 hold false ? Because success7 is an immutable variable.

In C #, ref draws attention to the fact that you are passing a variable reference as an argument to the ref parameter. It simply serves as insurance that the caller knows that the variable can be changed by the called method. In F #, however, ref creates a new reference cell containing a copy of the value of the next expression.

In this case, we create a reference cell that contains the value copied from the success7 variable, but without assigning this new reference cell to any variable. Then we pass this reference cell with the GetValue method, which changes the contents of the reference cell. Since the invocation method does not have variables pointing to the modified cell, it does not have the ability to read the new value of the reference cell.

+8
source share

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

So something like this will be more idiomatic

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

where instance.GetValue is

 unit -> ('a, bool) 

Or you can return the option and do something like

 match instance.GetValue(0x10) with | Some value -> doStuff value | None -> failwith "Oops!" 
+6
source share

You must use the link.

 let success = ref false instance.GetValue(0x10, success) // access the value !success 
+5
source share

I think it is also worth mentioning here that the value of the out parameter does not need to be initialized.

You can do the following:

 let mutable success3 = Unchecked.defaultof<bool> let result3 = o.GetValue (10, &success3) 

This can be useful in scenarios where you call the .NET library function with arrays as output parameters, i.e.:

 let mutable currFeatures = Unchecked.defaultof<PointF[]> let mutable status = Unchecked.defaultof<byte[]> let mutable trackError = Unchecked.defaultof<float32[]> CvInvoke.CalcOpticalFlowPyrLK( previousFrame, nextFrame, previousPoints, Size(15,15), 2, MCvTermCriteria(10, 0.03), //Out params &currFeatures, &status, &trackError, //--------- LKFlowFlag.UserInitialFlow) 
+1
source share

All Articles