making a mutable struct, in F#, vs. a class - f#

Let's imagine this recursive function:
let rec doSomething dataList b c d e f g h i =
// go through dataList and recurse with updated parameters
So we can make it cleaner:
type Context = { b:..; c:..; ... }
let rec doSomething dataList context =
// recurse with an updated context object
In practice this is slower since the context object has to be re-created every time and with very tight loops with simple calculations the overhead is visible.
I have several math loops done like this but now I have a new scenario coming up:
I need to use them on data that gets streamed in by using the same logic, but step by step as the data is coming.
So my function would be something like:
let doOneStepOfSomething oneData context : result * Context =
process one piece of data and returns the context object for the next iteration
But then I have also the object re-creation issue and I need to keep different contexts.
Is that a valid use case for a class where each instance could have its context variables as mutable? or would it make sense to make a mutable type with mutable fields instead for the context?

For any performance related question, the only answer is that you have to test it to see. I tested four different approaches using a simple function and the #time feature.
Immutable functional record
type C = { a:int; b:int; c:int; d:int }
let rec foo c =
if c.a > 100000000 then c
else foo { a = c.a + 1; b = c.a; c = c.a; d = c.a }
foo { a=0; b=0; c=0; d=0 } // ~1.1 sec
Function with inline parameters
let rec bar a b c d =
if a > 100000000 then (a,b,c,d)
else bar (a+1) a a a
bar 0 0 0 0 // ~200ms
Using an immutable struct to replace record
[<Struct>]
type S(a:int,b:int,c:int,d:int) =
member x.A = a
member x.B = b
member x.C = c
member x.D = d
let rec goo (c:S) =
if c.A > 100000000 then c
else goo (S(c.A+1, c.A, c.A, c.A))
goo (S(0,0,0,0)) // ~1.6sec
Using a mutable record
type M = { mutable a:int; mutable b:int; mutable c:int; mutable d:int }
let rec zoo c =
if c.a > 100000000 then c
else
c.a <- c.a + 1
c.b <- c.a
c.c <- c.a
c.d <- c.a
zoo c
zoo { a=0; b=0; c=0; d=0 } // ~1 sec
From these four tests, it seems that inline parameters are more efficient than anything else (which is pretty much all the same). So I would just use an immutable record, which makes the code clear and optimize this only if it proved to be an issue more generally in your system.

Related

How do I make a mutable argument in a function through F#?

Sorry for my question but I did not understand the answers that was related to this question so I hope someone can enlighten me further.
I am a new data science student and we are going to learn how to program in the functional language F#. We are learning about algorithms and I wanted to write the algorithms as F# functions to check if my calculations on paper were correct.
I get the following error saying:
"This value is not mutable. Consider using the mutable keyword let mutable n = expression"
My code looks like this:
let loop5( n ) =
let mutable x = 0
while n > 0 do
x <- x + 1
n <- n + 1
printfn "loop5(): x=%i for n=%i" x n
loop5(4)
I'm trying to write a function looking like this (pseudocode):
loop5(n)
x = 0
while n > 0
x = x + 1
n = n + 1
return x
Hope I made a clear question and someone can help me out here :-) Have a nice weekend
You're trying to mutate the loop's parameter n. The parameter is not mutable, so the compiler doesn't let you. That's exactly what the error tells you.
Now, normally, to make the error go away, you'd make the variable mutable. However, you can't make a function parameter mutable, so that's not an option.
Here you want to think what the meaning of your program should be. Does the loop function need to pass the updated value of n back to its caller, or is the whole mutation its internal business? If it's the former, please see #AnyMoose's answer, but from your example and explanation, I suspect it's the latter. If that is the case, simply make a mutable copy of the parameter and work with it:
let loop n' =
let mutable x = 0
let mutable n = n'
...
Separately, I want to point out that your program, as written, would actually loop indefinitely (or until it wraps around the max int value anyway), because instead of decreasing n at each step you're increasing it. If you want your program to actually finish before the next Ice Age, you need to make n decrease with each iteration:
n <- n - 1
Ref cells
Ref cells get around some of the limitations of mutables. In fact, ref cells are very simple datatypes which wrap up a mutable field in a record type. Ref cells are defined by F# as follows:
type 'a ref = { mutable contents : 'a }
The F# library contains several built-in functions and operators for working with ref cells:
let ref v = { contents = v } (* val ref : 'a -> 'a ref *)
let (!) r = r.contents (* val (!) : 'a ref -> 'a *)
let (:=) r v = r.contents <- v (* val (:=) : 'a ref -> 'a -> unit *)
The ref function is used to create a ref cell, the ! operator is used to read the contents of a ref cell, and the := operator is used to assign a ref cell a new value. Here is a sample in fsi:
let x = ref "hello";;
val x : string ref
x;; (* returns ref instance *)
val it : string ref = {contents = "hello";}
!x;; (* returns x.contents *)
val it : string = "hello"
x := "world";; (* updates x.contents with a new value *)
val it : unit = ()
!x;; (* returns x.contents *)
val it : string = "world"
Since ref cells are allocated on the heap, they can be shared across multiple functions:
open System
let withSideEffects x =
x := "assigned from withSideEffects function"
let refTest() =
let msg = ref "hello"
printfn "%s" !msg
let setMsg() =
msg := "world"
setMsg()
printfn "%s" !msg
withSideEffects msg
printfn "%s" !msg
let main() =
refTest()
Console.ReadKey(true) |> ignore
main()
The withSideEffects function has the type val withSideEffects : string ref -> unit.
This program outputs the following:
hello
world
Assigned from withSideEffects function
The withSideEffects function is named as such because it has a side-effect, meaning it can change the state of a variable in other functions. Ref Cells should be treated like fire. Use it cautiously when it is absolutely necessary but avoid it in general. If you find yourself using Ref Cells while translating code from C/C++, then ignore efficiency for a while and see if you can get away without Ref Cells or at worst using mutable. You would often stumble upon a more elegant and more maintanable algorithm
Aliasing Ref Cells
Note: While imperative programming uses aliasing extensively, this practice has a number of problems. In particular it makes programs hard to follow since the state of any variable can be modified at any point elsewhere in an application. Additionally, multithreaded applications sharing mutable state are difficult to reason about since one thread can potentially change the state of a variable in another thread, which can result in a number of subtle errors related to race conditions and dead locks.
A ref cell is very similar to a C or C++ pointer. Its possible to point to two or more ref cells to the same memory address; changes at that memory address will change the state of all ref cells pointing to it. Conceptually, this process looks like this:
Let's say we have 3 ref cells looking at the same address in memory:
Three references to an integer with value 7
cell1, cell2, and cell3 are all pointing to the same address in memory. The .contents property of each cell is 7. Let's say, at some point in our program, we execute the code cell1 := 10, this changes the value in memory to the following:
Three references to an integer with value 10
By assigning cell1.contents a new value, the variables cell2 and cell3 were changed as well. This can be demonstrated using fsi as follows:
let cell1 = ref 7;;
val cell1 : int ref
let cell2 = cell1;;
val cell2 : int ref
let cell3 = cell2;;
val cell3 : int ref
!cell1;;
val it : int = 7
!cell2;;
val it : int = 7
!cell3;;
val it : int = 7
cell1 := 10;;
val it : unit = ()
!cell1;;
val it : int = 10
!cell2;;
val it : int = 10
!cell3;;
val it : int = 10

WebSharper: opaque type with equality checking for `===`

I need a datatype that will be completely opaque in F# with equality defined in terms of JS ===. WebSharper manual says that I should override Equals but I can't make it work.
let x : OpaqueType = X<_>
let f (y : OpaqueType) =
if x = y then // this line should be translated to `if (x === y)`
42
else
10
So, what is the correct definition of OpaqueType?
Of course, I can use obj and add an inline function that will do x === y but I'd like to have something more awesome.
I would go for something like this:
module Test =
open IntelliFactory.WebSharper
[<JavaScript>]
let Counter = ref 0
[<Sealed>]
[<JavaScript>]
type T() =
let hash =
incr Counter
Counter.Value
[<JavaScript>]
override this.GetHashCode() =
hash
[<JavaScript>]
override this.Equals(other: obj) =
other ===. this
[<JavaScript>]
let Main () =
let a = T()
let b = T()
JavaScript.Log(a, b, a = b, a = a, hash a, hash b)
Equality and hashing are expected to be consistent by .NET libraries (for example, for use in Dictionary). They are also associated with types through virtual methods, so inlining will not work correctly. The above code gives you a type with reference-like equality semantics.

Make WebSharper generate simple field access

I need a type that will be translated into a plain JS object so that F# field access will be translated into simple JS field access (this is necessary, since the object will be sent through postMessage, so it'll lose all its methods).
Again, I need
let x = a.b
to be translated into
var x = a.b;
without any method calls.
Here is a slightly modified example from the F# Reference:
namespace T
open IntelliFactory.WebSharper
[<JavaScript>]
module A =
type MyClass =
val a : int
val b : int
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
let x = myClassObj.b
This won't translate with
x: error : Failed to translate property access: b.'
Ok, let's make those vals mutable:
namespace T
open IntelliFactory.WebSharper
[<JavaScript>]
module A =
type MyClass =
val mutable a : int
val mutable b : int
new(a0, b0) = { a = a0; b = b0; }
let myClassObj = new MyClass(35, 22)
let x = myClassObj.b
This will be successfully translated, but… MyClass.New returns an empty object. The question now starts looking much like a bugreport, right? So, back to the question.
Are there any other ways to achieve what I want?
There are additional issues with record-style constructors "{x = y}". I will have to look into this again on F# 3.0, the older F# did not produce sensible quotations for those and we did some partial workarounds in WebSharper. Right now your example breaks. So here is the working code with a static method instead of a constructor:
type MyClass private () =
[<DefaultValue>]
val mutable a : int
[<DefaultValue>]
val mutable b : int
static member Create(a0, b0) =
let c = MyClass()
c.a <- a0
c.b <- b0
c
let test () =
let myClassObj = MyClass.Create(35, 22)
let x = myClassObj.a
let y = myClassObj.b
JavaScript.Log(x, y)
Trivially, a record would also work.
In some cases where you want to go really low-level you can annotate members with the Inline attribute. When this is too much overhead you can use untyped API:
let x = obj ()
x?a <- 1
let y = x?a
JavaScript.Log(x, y)
try this:
type MyClass (a, b) =
member val A = a with get
member val B = b with get
let myClassObj = new MyClass(35, 22)
let x = myClassObj.B

Mutable states in F# object expressions

I would like to have a mutable state in an F# object expression.
The first approach is to use ref cells as follows:
type PP =
abstract member A : int
let foo =
let a = ref 0
{ new PP with
member x.A =
let ret = !a
a := !a + 1
ret
}
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
printfn "%A" foo.A
A different approach would be as follows:
type State(s : int) =
let mutable intState = s
member x.state
with get () = intState
and set v = intState <- v
[<AbstractClass>]
type PPP(state : State) =
abstract member A : int
member x.state
with get () = state.state
and set v = state.state <- v
let bar n =
{ new PPP(State(n)) with
member x.A =
let ret = x.state
x.state <- ret + 1
ret
}
let barA1 = bar 0
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
printfn "%A" barA1.A
Which version would be likely more performing (I need the state updating x.state <- ret + 1
in performance critical sections)? My guess is that the State object is also allocated on the heap so there is no reason why the second version should be faster. However it is slightly more appealing to use.
Thanks for any feedback and suggestions
As Daniel said, the last approach is essentially equivalent to using built-in ref.
When using ref, you're allocating two objects - the one that you're returning and the reference cell itself. You can reduce this to just a single allocated object by using a concrete implementation (but I don't think this will matter in practice):
type Stateful(initial:int) =
let mutable state = initial
interface PP with
member x.A =
let ret = state
state <- state + 1
ret
let foo =
Statefull(0) :> PP // Creates a single object that keeps the state as mutable field
Aside, you are using read-only property that modifies internal state of the object and returns a new state each time. This is a dangerous pattern that could be quite confusing - properties with getter shouldn't modify the state, so you should probably use a method (unit -> int) instead.
Your State class is identical to ref. They're both reference types (you can't capture a mutable value type from an object expression). I would prefer a built-in type when possible. ref is the idiomatic way to represent a heap-allocated mutable value.
If ever in doubt about performance, benchmark it.

F# mutable function arguments

Is there a way to have mutable function arguments in F#, that would allow something like
let mutable i = 9
let somefun n = n <- 12; ()
somefun i
(* *not* a real-world example *)
I do understand that this can be made to work by wrapping it into a record type
type SomeRec = { mutable i: int }
let ri = { i = 9 }
let someotherfun r = r.i <- 12; ()
and that this can be done in a similar fashion for class members. However, even after browsing through the whole F# Language Specification (yes, I did!), there seems to be no syntax to allow the first case, and the compiler appears to be quite unhappy about my trying this. I was hoping there would be some sort of type annotation, but mutable cannot be used in such.
I also know that I should not be doing this sort of thing in the first place, but the first case (int binding) and the second (record type) are semantically identical, and any such objection would hold for both cases equally.
So I think that I am missing something here.
You can use ref as arguments
let v = ref 0
let mutate r =
r := 100
mutate v
printfn "%d" !v
Or byref keyword
let mutable v = 0
let mutate (r : byref<_>) =
r <- 100
mutate &v
printfn "%d" v
Use byref keyword which is equivalent to C# ref.
See Passing by reference.

Resources