Reputation: 1708
I have a function GetCars which does not return the updated state. If I add a parameter, it works fine, or if I execute the same code in the other functions it works fine.
open System
open System.Collections.Concurrent
type Car = {
Make : string
Model : string
ID : int
}
type Cars = {
Count : int
Collection : Car[]
}
module AppState = begin
let state = new ConcurrentDictionary<string, obj>()
let added = state.TryAdd("cars", {
Count = 1
Collection = [| { Make = "Honda"; Model = "Civic"; ID = 0 } |]
})
let DownCastCars (o : obj) =
match o with
| :? Cars as cars -> Some(cars)
| _ -> None
let GetCars =
let mutable cars : obj = null;
let success = state.TryGetValue("cars", &cars)
if success then
DownCastCars cars
else
None
let AddCar car =
match GetCars with
| Some cars ->
state.TryUpdate("cars", { cars with Collection = Array.append cars.Collection [| car |] }, cars)
| None ->
false
end
let AddCarMakeModel make model =
let car : Car = {
Make = make
Model = model
ID = match AppState.GetCars with
| Some cars -> cars.Collection.Length
| None -> 0
}
let success = AppState.AddCar car
if success then
printfn "Successfully added car :)"
else
printfn "Failed to add car :("
[<EntryPoint>]
let main argv =
AddCarMakeModel "Honda" "Civic"
AddCarMakeModel "Honda" "Civic LX"
printfn "Press any key to continue"
let s = Console.ReadLine()
0 // return an integer exit code
If I add a parameter to GetCars i.e
let GetCars notused =
let mutable cars : obj = null;
let success = state.TryGetValue("cars", &cars)
if success then
DownCastCars cars
else
None
Then the GetCars function will return the newest value every time. Or if I just place the same code inside the other methods I am using i.e
let AddCarMakeModel Make Model =
let car : Car = {
Make = make
Model = model
ID = match AppState.GetCars with
| Some cars -> cars.Collection.Length
| None -> 0
}
let success = AppState.AddCar car
if success then
printfn "Successfully added car :)"
else
printfn "Failed to add car :("
I am guessing this has to do with "Do Bindings" but I am not sure how to apply that successfully to GetCars. I did notice GetCars get called when the application starts, and if I set a break point inside the function it never gets that far again.
Upvotes: 0
Views: 88
Reputation: 26174
As already stated in the comments, the solution is to add a unit parameter.
The problem is that you are declaring a constant value, not a function value.
This is evident if you look at its signature: val GetCars : Cars option
There is no arrow, just a value, so GetCars
will be executed only once and bound to the value on the right side of the expression.
By adding a unit parameter you get the signature: val GetCars : unit -> Cars option
so now at the call site you can refer either to the function value by GetCars
alone or to execute it and get its result by GetCars()
.
Also note you don't need the mutable since F# treat functions returning a value and a ref as a tuple, you can write GetCars
like this:
let GetCars() =
match state.TryGetValue("cars") with
| true, (:? Cars as cars) -> Some cars
| _ -> None
And then get rid of the function DownCastCars
.
Upvotes: 2