How do I go about using the TryTake method on a BlockingCollection<'a> passing in a timeout period in milliseconds?
Heres the signature:
BlockingCollection.TryTake(item: byref, millisecondsTimeout: int) : bool
is it possible to use the Tuple method of avoiding passing a ref type like on the Dictionary.TryGet methods?
i.e.
let success, item = myDictionary.TryGetValue(client)
Im struggling with this particular signature, any suggestions would be great.
Cheers!
I believe that you can only use that technique for byref parameters which occur at the end of the parameter list (this is similar to the rule for optional parameters). So if BlockingCollection.TryTake were defined with signature int * 'T byref -> bool it would work, but since it's defined as 'T byref * int -> bool it won't.
For example:
open System.Runtime.InteropServices
type T =
static member Meth1(a:int, [<Out>]b:string byref, [<Out>]c:bool byref) : char =
b <- sprintf "%i" a
c <- a % 2 = 0
char a
static member Meth2([<Out>]b:string byref, [<Out>]c:bool byref, a:int) : char =
b <- sprintf "%i" a
c <- a % 2 = 0
char a
// ok
let (r,b,c) = T.Meth1(5)
// ok
let (r,c) = T.Meth1(5,ref "test")
// ok
let r = T.Meth1(5, ref "test", ref true)
// doesn't compile
let (r,b,c) = T.Meth2(5)
// doesn't compile
let (r,c) = T.Meth2(ref "test", 5)
// ok
let r = T.Meth2(ref "test", ref true, 5)
Related
I have some code wrapping TA-Lib and a lot of the wrappers are very similar:
let sma (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Sma(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
let ema (timePeriod: int) (data: float[]) =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable emaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = Core.Ema(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, emaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding emaData
What I could like to do is create a generic function where I can just pass the TA-Lib function to call. Something like:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let mutable outStartIndex = 0
let mutable outNbElement = 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, &outStartIndex, &outNbElement, smaData)
if retCode <> Core.RetCode.Success then
invalidOp (sprintf "AssertRetCodeSuccess")
let padding = Array.create (timePeriod - 1) System.Double.NaN
Array.append padding smaData
but the error I am getting is:
[FS0412] A type instantiation involves a byref type. This is not permitted by the rules of Common IL.
Is there a workaround for this? I am not familiar with this issue.
Short answer: replace your mutable parameters with ref.
TA-Lib has a very unfortunate API: those pesky out-parameters (known in F# as byref), they always make trouble. In this case, they cannot be part of a generic type instantiation.
Here's a much shorter example. Consider a good old list<T>. We can make an empty list<int>:
let noInts = [] : list<int>
But what if those ints are byref?
let noRefs = [] : list< byref<int> >
No can do - says the compiler. A type instantiation involves a byref type. This is not permitted by the rules of Common IL. Sorry.
In your case, the last parameter of myGenericFunction is an F# function. In F# functions are represented by the type FSharpFunc<T, R> (where T is argument and R is result). So the type of your last parameter is this:
FSharpFunc< int * int * float array * int * byref<int> * byref<int> * float array, int >
See those two byref<int>s in there? Those are &outStartIndex and &outNbElement. And they are forbidden in a generic instantiation. Tough luck.
But there is hope!
The mutable keyword is only one of two ways to make mutable cells in F#. The other way is ref:
let x = ref 0 // Initialization
printfn "%d" !x // Prints "0"
x := 42 // Mutation
printfn "%d" !x // Prints "42"
It's an old-school thing, predates mutable, is implemented as a library (as opposed to a language construct), and in most cases mutable is better. But this is not one of those cases!
It turns out that:
Unlike true .NET CIL out-parameters, ref cells can be part of generic instantiation just fine. Because, from .NET point of view, they're nothing special - just another class.
The F# compiler has special sauce for them: when the expected type is a ref, but you're trying to pass a function with an out-parameter in its place, the compiler will automatically generate some wrapping code for you.
So, armed with this knowledge, you can modify myGenericFunction like this:
let myGenericFunction (timePeriod: int) (data: float[]) TALibFunc =
let outStartIndex = ref 0
let outNbElement = ref 0
let mutable smaData : float array = Array.zeroCreate (data.Length - timePeriod + 1)
let retCode = TALibFunc(0, (data.Length - 1), data, timePeriod, outStartIndex, outNbElement, smaData)
...
And then the consumers can call it like this:
myGenericFunction 42 [|1; 2; 3|] Core.Sma // Wrapping code gets generated here
I have the following F# Code that is causing a compile error:
persistence.fs(32,21): error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
The error is at the line "serializer.write...."
Any help would be appreciated.
namespace persisitence
open System.Collections.Generic
open System
open System.IO
type LocalData<'T> =
struct
val mutable elements_ : 'T list
val mutable lock_ : obj
new(e: 'T list) = { elements_ = e ; lock_ = new obj() }
end
type BinaryPersistenceOut<'T, ^W when ^W: (member write : ('T * BinaryWriter) -> unit)>(fn: string, serializer: ^W) as this =
let writer_ = new BinaryWriter(File.Open(fn, FileMode.Append))
let mutable localdata_ = new LocalData<'T>([])
let serializer_ = serializer
let NUM_SECS_IN_MIN = 60
let NUM_MSECS_IN_SEC = 1000
let NUM_MIN_BETWEEN_COMMITS = 2
let TIME_TO_WAIT = 15
let closed_ = false
let freq_ = NUM_MIN_BETWEEN_COMMITS * NUM_SECS_IN_MIN * NUM_MSECS_IN_SEC
let path_ = fn
let timer_ = new System.Timers.Timer((float) (NUM_MIN_BETWEEN_COMMITS * NUM_MSECS_IN_SEC) )
let writetofile =
fun (arg: Timers.ElapsedEventArgs ) ->
lock localdata_.lock_ ( fun () ->
if closed_ = false then
for elem in localdata_.elements_ do
serializer.write(elem, writer_)
)
do
timer_.Elapsed.Add(writetofile)
Although it'd be nice if you could invoke the write function like serializer.write(elem, writer_), you can't. You have to invoke it like this instead:
(^W: (member write : ('T * BinaryWriter) -> unit) (serializer, (elem, writer_)))
Full code block:
type BinaryPersistenceOut<'T, ^W when ^W: (member write : ('T * BinaryWriter) -> unit)> (fn: string, serializer: ^W) as this =
let writer_ = new BinaryWriter(File.Open(fn, FileMode.Append))
let mutable localdata_ = new LocalData<'T>([])
let serializer_ = serializer
let NUM_SECS_IN_MIN = 60
let NUM_MSECS_IN_SEC = 1000
let NUM_MIN_BETWEEN_COMMITS = 2
let TIME_TO_WAIT = 15
let closed_ = false
let freq_ = NUM_MIN_BETWEEN_COMMITS * NUM_SECS_IN_MIN * NUM_MSECS_IN_SEC
let path_ = fn
let timer_ = new System.Timers.Timer((float) (NUM_MIN_BETWEEN_COMMITS * NUM_MSECS_IN_SEC) )
let writetofile =
fun (arg: Timers.ElapsedEventArgs ) ->
lock localdata_.lock_ ( fun () ->
if closed_ = false then
for elem in localdata_.elements_ do
(^W: (member write : ('T * BinaryWriter) -> unit) (serializer, (elem, writer_)))
)
do
timer_.Elapsed.Add(writetofile)
Caveat: this compiles, but I have no idea if it does what you want it to do.
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#?
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.
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!"
You have to use a reference cell.
let success = ref false
instance.GetValue(0x10, success)
// access the value
!success
I think it's also worth mentioning here that the value of the out parameter doesn't have to be initialized.
It is possible to do the following:
let mutable success3 = Unchecked.defaultof<bool>
let result3 = o.GetValue (10, &success3)
This might be usefull in scenarios where you are calling a .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)
I would like to define one of my parameters to be a C# out parameter in one of my interfaces. I realize that F# supports byref but how can I apply the System.Runtime.InteropServices.OutAttribute to one of my interface parameters?
C# Interface I am trying to replicate
public interface IStatisticalTests
{
void JohansenWrapper(
double[,] dat,
double alpha,
bool doAdfPreTests,
out double cointStatus,
out JohansenModelParameters[] johansenModelParameters);
}
Here's an example:
open System
open System.Runtime.InteropServices
[<Interface>]
type IPrimitiveParser =
//
abstract TryParseInt32 : str:string * [<Out>] value:byref<int> -> bool
[<EntryPoint>]
let main argv =
let parser =
{ new IPrimitiveParser with
member __.TryParseInt32 (str, value) =
let success, v = System.Int32.TryParse str
if success then value <- v
success
}
match parser.TryParseInt32 "123" with
| true, value ->
printfn "The parsed value is %i." value
| false, _ ->
printfn "The string could not be parsed."
0 // Success
Here's your interface, translated:
[<Interface>]
type IStatisticalTests =
//
abstract JohansenWrapper :
dat:float[,] *
alpha:float *
doAdfPreTests:bool *
[<Out>] cointStatus:byref<float> *
[<Out>] johansenModelParameters:byref<JohansenModelParameters[]>
-> unit
in F#, I want to make a type of indexed array, so I can access the element by either .[i] or .[index_names] and by slice notation with index .. Is it possible to overwrite .[] like this? thanks.
define overloaded indexer in your type:
type MyIndexedArray<'T>() =
member this.Item(i : int) : 'T = Unchecked.defaultof<_>
member this.Item(name : string) : 'T = Unchecked.defaultof<_>
member this.GetSlice(a : int option, b : int option) : 'T = Unchecked.defaultof<_>
let arr = new MyIndexedArray<int>()
let a = arr.[1]
let b = arr.["name"]
let c = arr.[1..2]
let d = arr.[1..]
let e = arr.[..3]
let f = arr.[*]