F# and SignalR Stock Ticker: Part 2
December 3, 2013 1 Comment
Following up on my prior post found here about using F# to write the Stock Ticker example found on SignalR’s website, I went to implement the heart of the application – the stock ticker class.
The original C# class suffers from a violation of command/query separation and also does a couple of things. Breaking out the code functionality, the class creates a list of random stocks in the constructor.
Then there is a timer that loops and periodically updates the current stock price.
Finally, it broadcasts the new stock price to any connected clients.
Because the class depends on the clients for its creation and lifetime, it implements the singleton pattern – you access the class via its Instance property. This is a very common pattern:
- //Singleton instance
- private readonly static Lazy<StockTicker> _instance =
- new Lazy<StockTicker>(() =>
- new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));
- public static StockTicker Instance
- {
- get
- {
- return _instance.Value;
- }
- }
Attacking the class from a F# point of view, I first addressed the singleton pattern. I checked out the Singleton pattern in Liu’s F# for C# Developers. The sentience that caught my eye was “An F# value is immutable by default, and this guarantees there is only on instance.” (p149) Liu then goes and builds an example using a private class and shows how to reference it via a Instance method. My take-away from the example is that you don’t need a Singleton pattern in F# – because everything is Singleton by default. Another way to look at it is that a Singleton pattern is a well-accepted workaround the limitations that mutability brings when using C#.
I then jumped over to the updating stock prices – after all, how can you send out a list of new stock prices if you can’t mutate the list or the individual stocks within the list? Quite easily, in fact.
The first thing I did was to create a StockTicker class that takes in a SignalR HubContext and a list of stocks.
- type StockTicker(clients: IHubConnectionContext, stocks: IEnumerable<Stock>) = class
I then added the logic to update the list and stocks.
- let rangePercent = 0.002
- let updateInterval = TimeSpan.FromMilliseconds(250.)
- let updateStockPrice stock:Stock =
- let updateOrNotRandom = new Random()
- let r = updateOrNotRandom.NextDouble();
- match r with
- | r when r <= 1. -> stock
- | _ ->
- let random = new Random(int(Math.Floor(stock.Price)))
- let percentChange = random.NextDouble() * rangePercent
- let pos = random.NextDouble() > 0.51
- let change = Math.Round(stock.Price * decimal(percentChange),2)
- let newPrice = stock.Price + change
- new Stock(stock.Symbol, stock.DayOpen, newPrice)
- let updatedStocks = stocks
- |> Seq.map(fun stock -> updateStockPrice(stock))
Looking at the code, the word “update” in the prior sentence is wrong. I am not updating anything. I am replacing the list and the stocks with the new price (if determined). Who needs a singleton? F# doesn’t.
I then attempted to notify the clients like so:
- member x.Clients = clients
- member x.Stocks = stocks
- member x.BroadcastStockPrice (stock: Stock) =
- x.Clients.All.updateStockPrice(stock)
But I got a red squiggly line of approbation (RSLA) on the updateStockPrice method. The compiler is complaining that
Error 1 The field, constructor or member ‘updateStockPrice’ is not defined
And reading the SignalR explanation here:
The updateStockPrice method that you are calling in BroadcastStockPrice doesn’t exist yet; you’ll add it later when you write code that runs on the client. You can refer to updateStockPrice here because Clients.All is dynamic, which means the expression will be evaluated at runtime
So how does F# accommodate the dynamic nature of Clients.All? I don’t know so off to StackOverflow I go….
In any event, I can then wire up a method that broadcasts the new stock prices like so:
- member x.BroadcastAllPrices =
- x.Clients.All.updateAllStockPrices(updatedStocks)
And then write a method that calls this broadcast method every quarter second:
- member x.Start =
- async {
- while true do
- do! Async.Sleep updateInterval
- x.BroadcastAllPrices
- } |> Async.StartImmediate
Note that I tried to figure out the Timer class and subsequent Event for the timer, but I couldn’t. I stumbled upon this post to ditch the timer in favor of the code above and since it works, I am all for it. Figuring out events in F# is a battle for another day…