{"id":1147,"date":"2014-01-21T22:33:12","date_gmt":"2014-01-21T22:33:12","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=1147"},"modified":"2014-01-21T22:33:12","modified_gmt":"2014-01-21T22:33:12","slug":"event-and-event-handling-in-f","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/event-and-event-handling-in-f\/","title":{"rendered":"Event and event handling in F#"},"content":{"rendered":"<p><strong>Publishing events<\/strong><\/p>\n<p>Let&#8217;s look at the subject of event handling by starting with some code<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\ntype Application() =\r\n    let state = new Event&lt;_&gt;()\r\n    \r\n    member this.State = state.Publish\r\n    member this.Run() =\r\n        state.Trigger(this, &quot;Starting&quot;)\r\n        state.Trigger(this, &quot;Running&quot;)\r\n        state.Trigger(this, &quot;Finished&quot;)\r\n<\/pre>\n<p>So we&#8217;ve declared an Application object which has a private state value, of type Event<_>. Basically this is declaring a value as an Event, the <_> leaves it to the compiler to infer the usage, ofcourse you can explicitly state the type if you prefer.<\/p>\n<p><em>An Event is an implementation of IEvent, which is itself derived from an IDelegateEvent and IObservable. <\/p>\n<p>The IDelegateEvent has a special use when you mark properties with the attribute [&lt;CLIEvent&gt;]. The properties are now compatible with other languages which use CLI compatible events.<\/p>\n<p>The IObservable allows an event to be composable using Reactive Extensions (Rx) or using F#&#8217;s subset of Rx &#8211; this means we can filter, merge, split and more on events.<\/em><\/p>\n<p>Going back to the code sample, we declare a member property using <em>this.State = state.Publish<\/em> which basically binds to the Publish property which itself allows us to use the Add method to add event handlers. Had we wished to make this property CLI compliant we would write<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\n&#x5B;&lt;CLIEvent&gt;]\r\nmember this.State = state.Publish\r\n<\/pre>\n<p>The next piece of code in our example is a Run function and this simply triggers events in a way analogous to state changing during the function.<\/p>\n<p>Let&#8217;s now look at some code for handling these &#8220;state&#8221; change events&#8230;<\/p>\n<p><strong>Subscribing to events<\/strong><\/p>\n<p>Assuming we&#8217;ve created an instance of the application object, as follows<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\nlet app = new Application()\r\n<\/pre>\n<p>we can now subscribe to events on the object by adding an event handler<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\napp.State.Add(fun (sender, obj) -&gt; printfn &quot;%s&quot; obj)\r\n<\/pre>\n<p>in this example we use the Add function to subscribe to the State event and in this example we supply an anonymous function which is called each time a trigger is fired on the Application object&#8217;s State event. <\/p>\n<p>Now the Add function doesn&#8217;t have an equivalent remove, but as an alternative we could use the IDelegateEvent&#8217;s AddHandler and RemoveHandler as per the following<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\nlet handler = new Handler&lt;_&gt;(fun s o -&gt; printfn &quot;%s&quot; (snd o))\r\napp.State.AddHandler(handler)\r\n\r\n\/\/ ...\r\n\r\napp.State.RemoveHandler(handler)\r\n<\/pre>\n<p>We can also use the more functional style Event module methods to both add and filter (for example) to only handle certain messages, as per<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\napp.State \r\n   |&gt; Event.filter(fun (sender, obj) -&gt; obj = &quot;Running&quot;)\r\n   |&gt; Event.add(fun (sender, obj) -&gt; printfn &quot;%s&quot; obj)\r\n<\/pre>\n<p>In this example we&#8217;re filtering the events to only handle the case when the message is &#8220;Running&#8221; and the add function simply subscribes to the resultant events and outputs the message.<\/p>\n<p><strong>Observable<\/strong><\/p>\n<p>We can also use the IObservable subscription based model for events using <\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\napp.State \r\n   |&gt; Observable.map(fun (sender, obj) -&gt; obj)\r\n   |&gt; Observable.filter(fun obj -&gt; obj = &quot;Running&quot;)\r\n   |&gt; Observable.add(fun obj -&gt; printfn &quot;%s&quot; obj)\r\n<\/pre>\n<p>In this sample code we map the events to extract the message string (using the map function), then we filter it and finally we add our event handler.<\/p>\n<p>And here&#8217;s an example using the subscribe function<\/p>\n<pre class=\"brush: fsharp; title: ; notranslate\" title=\"\">\r\napp.State \r\n   |&gt; Observable.map(fun (sender, obj) -&gt; obj)\r\n   |&gt; Observable.filter(fun obj -&gt; obj = &quot;Running&quot;)\r\n   |&gt; Observable.subscribe(fun obj -&gt; printfn &quot;%s&quot; obj)\r\n   |&gt; ignore\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Publishing events Let&#8217;s look at the subject of event handling by starting with some code type Application() = let state = new Event&lt;_&gt;() member this.State = state.Publish member this.Run() = state.Trigger(this, &quot;Starting&quot;) state.Trigger(this, &quot;Running&quot;) state.Trigger(this, &quot;Finished&quot;) So we&#8217;ve declared an Application object which has a private state value, of type Event. Basically this is declaring [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[6],"tags":[],"class_list":["post-1147","post","type-post","status-publish","format-standard","hentry","category-f"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/1147","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=1147"}],"version-history":[{"count":14,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/1147\/revisions"}],"predecessor-version":[{"id":1161,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/1147\/revisions\/1161"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=1147"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=1147"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=1147"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}