Clear all event handlers in F#? - f#

If I remember correctly from my C# days, there was a way to unsubscribe all event handlers from an event without the need to do a -= operation for each of them: assigning null to the event.
However, seems that in F# this is not possible? I find the methods Trigger, Publish, Subscribe, Add, and Remove. Would be handy to have a Clear one or something alike. Maybe it's easy to implement a custom event that can achieve this?

As far as I can see, there is no way to do this with standard F# Event<'T> type. Even when you define an event and mark it as CLIEvent, the generated code defines a custom type of event with add and remove methods and so there does not seem to be a way to remove all handlers.
However, if you need to define your own F# event that supports this, you can actually implement this yourself. You can implement something like Event<'T> which keeps track of event handlers using a ResizeArray and removes all handlers when asked to do that. All you need to do is to implement the IObservable (or if you want more methods, IEvent interface).
The following does not handle concurrency correctly and might break, but it shows the idea:
open System
type RemovableEvent<'T> () =
let handlers = ResizeArray<Handler<_>>()
member x.Trigger(v) =
for h in handlers do h.Invoke(x, v)
member x.Clear() =
handlers.Clear()
member x.Publish =
{ new IEvent<'T> with
member x.AddHandler(h) = handlers.Add(h)
member x.RemoveHandler(h) = handlers.Remove(h) |> ignore
member x.Subscribe(h) =
let h = Handler<_>(fun _ v -> h.OnNext v)
handlers.Add(h)
{ new IDisposable with
member x.Dispose() = handlers.Remove(h) |> ignore } }
let re = RemovableEvent<_>()
re.Publish.Add(printfn "Hello %s")
re.Publish.Add(printfn "Hello again %s")
re.Trigger("world")
re.Clear()

This quote really just confirms the answer by Tomas.
From Concurrency in .NET by Riccardo Terrell, Published by Manning Publications, 2018, Chapter 6
"It’s possible to choose (and use) either Observable or Event when using F# to build reactive systems; but to avoid memory leaks, the preferred choice is Observable. When using the F# Event module, composed events are attached to the original event, and they don’t have an unsubscribe mechanism that can lead to memory leaks. Instead, the Observable module provides the subscribe operator to register a callback function. This operator returns an IDisposable object that can be used to stop event-stream processing and to de-register all subscribed observable (or event) handlers in the pipeline with one call of the Dispose method."

Related

How to unsubscribe an event from inside the event handler?

My code subscribes to an event and it needs to unsubscribe (Dispose) once the event has been handled. However this looks like a chicken-egg problem. Using rec doesn't work and I cannot find how to do it.
It there any well-konwn pattern to bypass this limitation?
let process = new Process()
let exitSubscription = process.Exited.Subscribe (
fun evntArg ->
exitSubscription.Dispose() <---------- Compiler complains here
// do more something here.
)
(you're saying in your question that rec doesn't work, but do not clarify why or how; so I'm going to ignore that part for this answer)
One way to do this is to declare the value "recursive" with the rec keyword. This will allow the value initialization code to reference the value itself - just like with a recursive function.
let rec exitSubscription : IDisposable = process.Exited.Subscribe (
fun evntArg ->
exitSubscription.Dispose()
// do more something here.
)
This will work, but will also produce a warning saying "this is a recursive value, and I can't tell if you're actually accessing it while it's being constructed, so you have to make sure that you don't, and if you do anyway, it'll be a runtime error".
Note that you also have to add a type signature to the variable, otherwise the compiler can't quite grok it and complains that it might not have a Dispose method.
Another way is to make the variable mutable and then mutate it:
let mutable exitSubscription : IDisposable = null
exitSubscription <- process.Exited.Subscribe (
fun evntArg ->
exitSubscription.Dispose()
// do more something here.
)
Here you have to use a type signature too (for the same reason), and you have to initialize it with null, because there is no such thing as an uninitialized variable.
Also, this is a tiny bit less safe, because the variable is mutable, and that's always a source of bugs. As long as you pinky-promise not to mutate it (beyond this initialization), you're ok.
But a "proper" way is to use an observable combinator to limit the observable to only one element. That way you don't have to unsubscribe explicitly, which is always more reliable:
#r "nuget: System.Reactive"
open System.Reactive.Linq
process.Exited.Take(1).Subscribe (
fun evntArg ->
// do more something here.
)

How do I expose a function type as a business requirement without exposing its asynchronous dependency?

I prefer to model business requirements as function types within a code base:
type Subscribe = SubscribeRequest -> Result<SubscribedCourier,ErrorDescription>
Then I implemented a function that complies with a function type:
let subscribe : Publish.Subscribe =
fun request ->
let subscribed = request |> toSubscribedCourier
...
Ok subscribed
Issue:
The above function is fine when implementing a unit test. However, when the above function needs to rely on an external system to complete its task, then I believe that the function requires an async modifier for that function signature.
As a result, I'm now obligated to update my function type to the following:
type Subscribe = SubscribeRequest -> Async<Result<SubscribedCourier,ErrorDescription>>
Thus, my actual function that needs to await an external system's response looks like this:
let subscribe : Publish.Subscribe =
fun request ->
async {
let subscribed = request |> toSubscribedCourier
let json = JsonConvert.SerializeObject subscribed
let buffer = Encoding.ASCII.GetBytes(json)
let message = Message(buffer)
let topicClient = new TopicClient("MyConnectionString","Subscription.subscribed")
do! topicClient.SendAsync(message) |> Async.AwaitTask
return Ok subscribed
}
Although, the above function type is correct for returning an Async result type, it's now a leaky abstraction for how the function executes. I really want to only specify business requirements through function types and have my functions map to those function types as if they were contacts.
Question:
In conclusion, how do I expose a function type as a business requirement without exposing its asynchronous dependency?
I don't know why you want to define a type alias for a function, but I do agree that if you want to implement a functional architecture, business logic shouldn't be asynchronous. In F# I think that it makes sense to view asynchronicity as implying impurity. You rarely need to return asynchronous workflows unless you're performing I/O.
I think that one should keep the domain model pure, so, as you write, returning an asynchronous workflow is a leaky abstraction.
You can often address the issue by refactoring to an impure-pure-impure sandwich. This also seems to be the case here. As far as I can tell, the work to actually put a message on a queue looks to be entirely generic. I suppose you could extract that into a helper function, like this:
let send x =
let json = JsonConvert.SerializeObject x
let buffer = Encoding.ASCII.GetBytes json
let message = Message buffer
let topicClient = new TopicClient ("MyConnectionString", "Subscription.subscribed")
do! topicClient.SendAsync message |> Async.AwaitTask
return Ok x
(I haven't tried to compile this, so there may be minor issues.)
You can now create the sandwich as a straightforward composition:
let sandwich = toSubscribedCourier >> send
(Again, this may not compile, but hopefully gets the point across.)
It's possible that there's little to no logic in toSubscribedCourier, but that's just the reality of things, then. As I've written in a recent article on the same general topic:
Once you remove all the accidental complexity, you uncover the essential complexity.
Perhaps there isn't much domain logic, but that fact is only laid bare once you start separating the pure functions from the impure actions.

f# function not recognized as parameter

Please unwrap these type signatures to help me understand why this doesn't work.
Then, if you have a solution, that would be great too.
I have this code and the agent.Post command has the signature Observer.Create<'T>(onNext: Action<'T>) : IObserver<'T>
let reservatinoRequestObserver = Observer.Create agent.Post
interface IHttpControllerActivator with
To my knowledge, this means that Observer.Create should take an Action with a single generic parameter and then return an IObserver.
Now the definition of Post is member MailboxProcessor.Post : message:'Msg ->unit
So... Post is a method, no? It is a method that takes a single parameter no? And it returns void no? So shouldn't it be a candidate for Observer.Create? Isn't that the exact specification of Action<'T>?
Well, somethings up, I get This function takes too many arguments, or is used in a context where a function is not expected:
Help me out... I freely admit I suck at F#
First, agent.Post returns unit, which is a different thing from void. F# will usually convert back and forth between void and unit for you, but they are not the same thing.
Second, F# functions do not implicitly convert to .NET delegates.
But there are some ways to do it:
You can explicitly create the delegate using its constructor:
let o = Observer.Create (new Action<_>( agent.Post ))
Lambdas are nicely wrapped too
let o = Observer.Create (fun msg -> agent.Post msg)
Use F# Rx-wrappers
Also there are a couple of F# wrappers/interop for Rx on nuget - just have a look, I think any will do

Unable to use protected events in F#

Let's say we have the following C# class
public class Class1
{
protected event EventHandler ProtectedEvent;
protected virtual void OverrideMe() { }
}
It seems to be impossible to use the ProtectedEvent in F#.
type HelpMe() as this =
inherit Class1()
do
printfn "%A" this.ProtectedEvent
member x.HookEvents() =
printfn "%A" x.ProtectedEvent
member private x.HookEvents2() =
printfn "%A" x.ProtectedEvent
override x.OverrideMe() =
printfn "%A" x.ProtectedEvent
In this example I have attempted to call printfn on it, as there are multiple ways to hook up events in F# and I wanted to be clear that is simply the referencing of the event at all that causes the problem.
In each of the cases above the compiler complains with the following error
A protected member is called or 'base' is being used. This is only
allowed in the direct implementation of members since they could
escape their object scope.
I understand this error, what causes it and its purpose. Usually, the work around is to wrap the call in a private member, which works fine with methods - but that does not seem to work with events. No matter what I try, it seems to be impossible to use protected events in F# unless I resort to doing something with reflection, or make some changes to the base class (which in my case is not possible).
Note that I have also tried all possible combinations of using base, this and x.
Am I doing something wrong ?
I suspect that there is something about the code that the compiler generates behind the scene when you treat the event as a first-class value that later confuses it (i.e. some hidden lambda function that makes the compiler think it cannot access the protected member). I'd say that this is a bug.
As far as I can see, you can workaround it by using add_ProtectedEvent and remove_ProtectedEvent members directly (they do not show in the auto-completion, but they are there and are accessible - they are protected, but calling them is a direct method call, which is fine):
type HelpMe() =
inherit Class1()
member x.HookEvents() =
let eh = System.EventHandler(fun _ _ -> printfn "yay")
x.add_ProtectedEvent(eh)
override x.OverrideMe() =
printfn "hello"
This compiled fine for me. It is a shame that you cannot use the protected event as a first-class value, but this at least lets you use it...

Is there any way to use JavaScript attribute by default?

I just want somehow to say "I want all methods in this project use [JavaScript]"
Manually annotation every method is annoying
F# 3 lets you mark a module with the ReflectedDefinition attribute (aka [JavaScript] in WebSharper) which marks all the methods underneath.
See More About F# 3.0 Language Features:
(Speaking of uncommon attributes, in F# 3.0, the
[< ReflectedDefinition >] attribute can now be placed on modules and
type definitions, as a shorthand way to apply it to each individual
member of the module/type.)
I think Phil's answer is the way to go - when you can mark an entire module or type, it does not add too much noise and it also allows you to distinguish between server-side and client-side code in WebSharper.
Just for the record, the F# compiler is open-source and so someone (who finds this issue important) could easily create branch that would add an additional command line attribute to override the setting. I think this is just a matter of adding the parameter and then setting the default value of the reflect flag in check.fs (here is the source on GitHub).
At the moment, the main F# repository does not accept contributions that add new features (see the discussion here), but it is certainly a good way to send a feature request to the F# team :-)
If you annotate all your code with the JavaScript attribute, the WebSharper compiler will try to translate everything to JavaScript. A rule of thumb in WebSharper development is to separate server-side and client-side code, so you can simply annotate the module/class containing client-side code instead of every function/member if you're targeting .NET 4.5.
namespace Website
open IntelliFactory.WebSharper
module HelloWorld =
module private Server =
[<Rpc>]
let main() = async { return "World" }
[<JavaScript>] // or [<ReflectedDefinition>]
module Client =
open IntelliFactory.WebSharper.Html
let sayHello() =
async {
let! world = Server.main()
JavaScript.Alert <| "Hello " + world
}
let btn =
Button [Text "Click Me"]
|>! OnClick (fun _ _ ->
async {
do! sayHello()
} |> Async.Start)
let main() = Div [btn]
type Control() =
inherit Web.Control()
[<JavaScript>]
override __.Body = Client.main() :> _

Resources