What is the F# equivalent of the following C# code? Specifically, I need to check if an event is being handled.
protected virtual void OnClicked(ClickEventArgs e) {
if (this.Clicked != null) //how can I perform this check in F#
this.Clicked(this, e);
}
Okay, I think I figured this thing out. Taking a cue from Don Syme's blog, specifically the section "The Implementation of the IEvent Module."
Instead of the following:
let validationFailedEvent = new Event<DataValidationEventHandler, DataValidationEventArgs>()
I had to implement IEvent myself and create a variable to hold the invocation list:
let mutable listeners: Delegate = null
let validationFailedEvent = { new IEvent<DataValidationEventHandler, DataValidationEventArgs> with
member x.AddHandler(d) =
listeners <- Delegate.Combine(listeners, d)
member x.RemoveHandler(d) =
listeners <- Delegate.Remove(listeners, d)
member x.Subscribe(observer) =
let h = new Handler<_>(fun sender args -> observer.OnNext(args))
(x :?> IEvent<_,_>).AddHandler(h)
{ new System.IDisposable with
member x.Dispose() = (x :?> IEvent<_,_>).RemoveHandler(h) } }
Then, to check if there are listeners, and, if not, raise an exception:
member private x.fireValidationFailedEvent(e:DataValidationEventArgs) =
match listeners with
| null -> failwith "No listeners"
| d -> d.DynamicInvoke([| box x; box e |])
An alternative way to implement RequiresSubscriptionEvent is to build on top of the existing Event functionality (using composition) and just add a counter that counts the number of registered handlers and add a property HasListeners (or even publish the number of listeners if you wanted...)
This makes the code a bit easier to use and hopefuly also safer, because if you don't check whether it has any listneres, it will still work as the usual F# code. And if you want to perform the check, you can...
type RequiresSubscriptionEvent<_>() =
let evt = new Event<_>()
let mutable counter = 0
let published =
{ new IEvent<_> with
member x.AddHandler(h) =
evt.Publish.AddHandler(h)
counter <- counter + 1;
member x.RemoveHandler(h) =
evt.Publish.RemoveHandler(h)
counter <- counter - 1;
member x.Subscribe(s) =
let h = new Handler<_>(fun _ -> s.OnNext)
x.AddHandler(h)
{ new System.IDisposable with
member y.Dispose() = x.RemoveHandler(h) } }
member x.Trigger(v) = evt.Trigger(v)
member x.Publish = published
member x.HasListeners = counter > 0
Sample usage:
type Demo() =
let evt = new RequiresSubscriptionEvent<_>()
[<CLIEvent>]
member x.OnSomething = evt.Publish
member x.FooThatFiresSomething() =
if evt.HasListeners then
evt.Trigger("foo!")
else
printfn "No handlers!"
Even though this isn't a part of standard F# libraries, it shows the great advantage of F# first class events. If there is some missing functionality, you can simply implement it yourself!
Typically, you don't need to do that check in F# (the event infrastructure checks for you):
type T() =
let ev = new Event<_>()
[<CLIEvent>]
member x.Event = ev.Publish
member x.OnClicked() =
ev.Trigger()
I followed kvb's suggestion and put this logic in a class. I copied Event from the F# sources and added a Handled property, which checks if the Delegate is null. I tried adding to, then removing handlers from the event to make sure it gets set back to null, and indeed it does.
type EventEx<'Delegate,'Args when 'Delegate : delegate<'Args,unit> and 'Delegate :> System.Delegate >() =
let mutable multicast : System.Delegate = null
static let argTypes =
let instanceBindingFlags = BindingFlags.Instance ||| BindingFlags.Public ||| BindingFlags.NonPublic ||| BindingFlags.DeclaredOnly
let mi = typeof<'Delegate>.GetMethod("Invoke",instanceBindingFlags)
mi.GetParameters() |> (fun arr -> arr.[1..]) |> Array.map (fun p -> p.ParameterType)
member x.Handled = (multicast <> null)
member x.Trigger(sender:obj,args:'Args) =
match multicast with
| null -> ()
| d ->
if argTypes.Length = 1 then
d.DynamicInvoke([| sender; box args |]) |> ignore
else
d.DynamicInvoke(Array.append [| sender |] (Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(box args))) |> ignore
member x.Publish =
{ new IEvent<'Delegate,'Args> with
member x.AddHandler(d) =
multicast <- System.Delegate.Combine(multicast, d)
member x.RemoveHandler(d) =
multicast <- System.Delegate.Remove(multicast, d)
member e.Subscribe(observer) =
let h = new Handler<_>(fun sender args -> observer.OnNext(args))
(e :?> IEvent<_,_>).AddHandler(h)
{ new System.IDisposable with
member x.Dispose() = (e :?> IEvent<_,_>).RemoveHandler(h) } }
This article here http://geekswithblogs.net/Erik/archive/2008/05/22/122302.aspx says you do not need to check for null events in F#, though I don't know what his reference is.
This article http://blogs.msdn.com/dsyme/articles/FSharpCompositionalEvents.aspx by Don Symes goes into F# events in quite a bit of detail. It looks like events are not owned by the class in F#
From the above,
it is that events are now first-class
values in the F# langauge. Indeed,
events are not a separate notion at
all in the language design, rather,
events are just values of type
Microsoft.FSharp.Idioms.IEvent<_>, and
.NET events are effectively just
properties of this type.
And
One of the restrictions of C# is that
events can only exist as members
within classes. With the F# model,
new event values can be created just
as values as part of any expression.
Related
Getting into the bowels now. Hopefully this is the last time I have to deal with Reflection for a while and I can return to the high level where I belong.
I have a type "PrimaryKey" defined as such.
type PrimaryKey<'x> =
| Id of int
| EmptyPrimaryKey
Then a bunch of record types associated with database tables, for example:
type User = {
user_id: PrimaryKey<User>
username: string
email: string
address_id: PrimaryKey<Address>
} with
static member DatabaseTable = "users"
I have written a custom type handler for Dapper to handle the Primary Key type.
type PrimaryKeyHandler<'X>() =
inherit SqlMapper.TypeHandler<PrimaryKey<'X>>()
(* I don't think this works but that's a future problem *)
override _.SetValue(param, value) =
let valueOrNull =
match value with
| PrimaryKey.Id id -> box id
| EmptyPrimaryKey -> null
param.Value <- valueOrNull
override _.Parse value =
if isNull value || value = box DBNull.Value
then EmptyPrimaryKey
else Id (value :?> int)
Now the problem with that is I have to call::
SqlMapper.AddTypeHandler (PrimaryKeyHandler<User>())
SqlMapper.AddTypeHandler (PrimaryKeyHandler<OtherRecordType>())
On every record that has a primary key. I'm basing my solution off of this: Dapper generic typehandler for F# Union types
But I don't understand it enough to adapt it to my needs, I think I need extra handling for the generic type.
What I've started with is this:
let RegisterTypeHandlers () =
let assembly = Assembly.GetCallingAssembly()
let handler = typedefof<PrimaryKeyHandler<_>>
assembly.GetTypes()
|> Seq.filter(fun t ->
FSharpType.IsRecord(t) && t.GetProperty("DatabaseTable") <> null
)
Which successfully returns a list of record types which have database table associations.
However trying to iterate over that list and call AddTypeHandler on all of those types fails:
let RegisterTypeHandlers () =
let assembly = Assembly.GetCallingAssembly()
let handler = typedefof<PrimaryKeyHandler<_>>
assembly.GetTypes()
|> Seq.filter(fun t ->
FSharpType.IsRecord(t) && t.GetProperty("DatabaseTable") <> null
)
|> Seq.iter(fun t ->
printfn $"Type: {t.Name}"
let ctor = handler
.MakeGenericType(t)
.GetConstructor(Array.empty)
.Invoke(Array.empty)
(typeof<SqlMapper>.GetMethods()
|> Seq.filter(fun methodInfo ->
if methodInfo.Name = "AddTypeHandler" && methodInfo.IsGenericMethodDefinition then
let gp = methodInfo.GetParameters()
not <| isNull gp && gp.Length = 1 && gp.[0].ParameterType.Name.Contains("TypeHandler")
else false)
|> Seq.head)
.MakeGenericMethod(t)
.Invoke(null, [| ctor |]) |> ignore
)
The error being
Unhandled exception. System.ArgumentException: Object of type 'MyModule.Common+PrimaryKeyHandler`1[Program+User]' cannot be converted to type 'Dapper.SqlMapper+TypeHandler`1[Program+User]'.
I've been looking at some of the GenericType functions in reflection but not really sure where to go from here.
First of all, you are getting an error saying that PrimaryKeyHandler<User> cannot be converted to type TypeHandler<User>. This is correct, because your type PrimaryKeyHandler<User> inherits from TypeHandler<PrimaryKey<User>>.
I think this happens because you get the AddTypeHandler method via reflection and then use MakeGenericMethod(t) to make it generic - but if t is User, then you get the wrong generic instantiation - you need to wrap t with PrimaryKey<..> around it first.
I have not tested this, but I think the following should work:
let addTyMi =
typeof<SqlMapper>.GetMethods()
|> Seq.find(fun methodInfo ->
if methodInfo.Name = "AddTypeHandler" &&
methodInfo.IsGenericMethodDefinition then
let gp = methodInfo.GetParameters()
not <| isNull gp && gp.Length = 1 &&
gp.[0].ParameterType.Name.Contains("TypeHandler")
else false)
let pkt = typedefof<PrimaryKey<_>>.MakeGenericType(t)
addTyMi.MakeGenericMethod(pkt).Invoke(null, [| ctor |]) |> ignore
It seems to me that there is also a non-generic overload of AddTypeHandler taking System.Type (by browsing GitHub source - I have not tried this). Maybe you could do just:
let pkt = typedefof<PrimaryKey<_>>.MakeGenericType(t)
SqlMapper.AddTypeHandler(pkt, ctor)
...avoiding some of the reflection. Also, ctor is a bad name, because the variable refers to the instance!
When I'm working in F# Interactive, I often want to make changes to an event handler. Simply calling the Subscribe or Add or AddHandler functions on an event causes the old event to continue being called, which is rarely the intention.
One solution is to use the IDisposable that it returns, but that requires tracking the IDisposables in your own code, which is cumbersome for exploratory tasks.
I've tried making a Dictionary<IEvent,IDisposable> to call Dispose() when the same event is subscribed to again:
let events = Dictionary<obj, IDisposable>()
let subonce (e:IEvent<'h,'e>) (handler: 'e -> unit) =
if events.ContainsKey e then
events.[e].Dispose()
events.Remove e |> ignore
let d = e.Subscribe handler
events.Add (e,d) |> ignore
let w = Window()
w.Show()
//Running this line in FSI a second time onward should Dispose() the previous subscription
subonce w.MouseUp (fun e -> printfn "%A" <| e.GetPosition(w))
Unfortunately, as it turns out, F# generates a new IEvent instance, so naively using = or obj.Equals doesn't cut it.
> w.MouseUp;;
val it : IEvent<Input.MouseButtonEventHandler,Input.MouseButtonEventArgs> =
<published event> {addHandler = <fun:it#5-70>;
createHandler = <fun:it#5-72>;
removeHandler = <fun:it#5-71>;}
> w.MouseUp;;
val it : IEvent<Input.MouseButtonEventHandler,Input.MouseButtonEventArgs> =
<published event> {addHandler = <fun:it#6-74>; //note that these functions are of a different anonymous instance
createHandler = <fun:it#6-76>;
removeHandler = <fun:it#6-75>;}
Are there any properties or fields I can find within an IEvent that would identify it against other instances of the owner and against different events in that owner?
Not exactly an answer to the question, but I can't think of many other scenarios in which you'd need to identify an event instance, so maybe this is good enough:
type OneHandler<'e> = { mutable h : 'e -> unit }
let onehandler (e:IEvent<'h,'e>) =
let h = { h = fun _ -> () }
e.Subscribe(fun e -> h.h e) |> ignore
h
let w = Window()
let wmouseup = onehandler w.MouseUp
wmouseup.h <- (fun e -> printfn "%A" <| e.GetPosition(w))
This way, by evaluating just the assignment to wmouseup.h, we can change the event handler without having to restart the w or juggle IDisposable or Handler objects.
I'm trying to build a log4net style interface in an F# assembly. The key attribute is exposing a static method that returns an instance of an object. log4net makes use of C# delegates to accomplish the task, e.g. with LogManager.GetLogger("log123"). Delegates, from my understanding, are less favored than functions-as-first-class for inward-facing F# libraries.
The simplified code below accomplishes the objective, but I am uncomfortable with the use of an F# reference cell to hold a map of instantiated objects. I am interested in feedback on whether my discomfort is warranted.
namespace Test
[<Interface>]
type IMyIface =
abstract member Addi : int -> int
[<Sealed>]
type TheMainObject internal (x:int) =
let mutable sum = x
interface IMyIface with
member this.Addi(y:int) = sum <- sum + y; sum
module internal Wrapr =
let mymap = ref Map.empty
let mgr s =
let m = !mymap
if Map.containsKey s m then m.[s]
else
let x = new TheMainObject(0)
mymap := m.Add(s, x)
x
[<Sealed>]
type Mgr() =
static member Get(n:string) =
Wrapr.mgr n :> IMyIface
Program.fs calls the library above as follows:
open Test
let a = Mgr.Get("hello")
printfn "%d" (a.Addi(1))
let c = Mgr.Get("hello")
printfn "%d, %A" (c.Addi(3)) (a = c) //prints 4, true
Thanks in advance for comments.
It's OK to use a reference cell internally to hold a mutable value. You could also use a .Net Dictionary instead of a map. This is the approach I took while building a Mini IoC Container. If you expect the function accessing the reference cell to be called from multiple threads then you should probably use a lock or other thread synchronization.
There are a number of ways of exposing the Get method. The static member approach you have taken is useful if you expect to overload the method. In which case you may consider using static let for static locals over a separate module:
type [<Sealed>] Mgr() =
static let sync = obj()
static let lookup = Dictionary()
static let obtain name =
match lookup.TryGetValue(name) with
| true, x -> x
| false,_ ->
let x = TheMainObject(0)
lookup.Add(name,x)
x
static member Get(name:string) =
lock sync (fun () -> obtain name :> IMyIface)
If you do not expect to overload the Get function then you could just use a module:
module Mgr =
let private lookup = ref Map.empty
let private obtain name =
match (!lookup).TryFind name with
| Some(x) -> x
| None ->
let x = TheMainObject(0)
lookup := (!lookup).Add(name,x)
x
let Get name = obtain name :> IMyIface
From the MSDN documentation I understand that if Run is implemented it will be called automatically at the end of the computational expression. It says that:
builder.Run(builder.Delay(fun () -> {| cexpr |}))
will be generated for the computational expression. Run and/or Delay will be omitted if they are not defined in the workflow builder. I was expecting my ReaderBuilder to return a list of MyItem objects when Run is called automatically. So I do not understand why I'm getting a type mismatch error. The errors are generated by the return statement inside the ProcedureBuilder foo at the end of my code listing here. Could someone please explain what I'm misunderstanding about workflow builders and what I have implemented incorrectly?
I'm getting the following errors:
The type ''a list' is not compatible with the type 'ReaderBuilder'
Type constraint mismatch. The type 'a list is not compatible with type ReaderBuilder The type ''a list' is not compatible with the type 'ReaderBuilder'
open System
open System.Data
open System.Data.Common
open System.Configuration
let config = ConfigurationManager.ConnectionStrings.Item("db")
let factory = DbProviderFactories.GetFactory(config.ProviderName)
type Direction =
| In
| Out
| Ref
| Return
type dbType =
| Int32
| String of int
type ReaderBuilder(cmd) =
let mutable items = []
member x.Foo = 2
member x.YieldFrom item =
items <- item::items
item
member x.Run item =
items
type ProcBuilder(procedureName:string) =
let name = procedureName
let mutable parameters = []
let mutable cmd:DbCommand = null
let mutable data = []
member x.Command with get() = cmd
member x.CreateCommand() =
factory.CreateCommand()
member x.AddParameter(p:string*dbType*Direction) =
parameters <- p::parameters
member x.Bind(v,f) =
f v
member x.Reader = ReaderBuilder(cmd)
member x.Return(rBuilder:ReaderBuilder) =
data
let (?<-) (builder:ProcBuilder) (prop:string) (value:'t) =
builder.Command.Parameters.[prop].Value <- value
type MyItem() =
let mutable _a = 0
let mutable _b = String.Empty
let mutable _c = DateTime.Now
member x.a
with get() = _a
and set n = _a <- n
member x.b
with get() = _b
and set n = _b <- n
member x.c
with get() = _c
and set n = _c <- n
let proc name = ProcBuilder(name)
let (%) (builder:ProcBuilder) (p:string*dbType*Direction) =
builder.AddParameter(p)
builder
let (?) (r:DbDataReader) (s:string) = r.GetOrdinal(s)
let foo x y =
let foo = proc "foo" % ("x", Int32, In) % ("y", String(15), In)
foo?x <- x
foo?y <- y
foo {
do! foo?x <- x
do! foo?y <- y
return foo.Reader {
let item = MyItem()
item.a <- r.GetInt32("a")
item.b <- r.GetString("b")
item.c <- r.GetDateTime("c")
yield! item
}
}
The problem in your example is that the foo.Reader { ... } block has a return type MyItem list (because this is what the Run member of the ReaderBuilder type returns). However, the Return member of ProcBuilder expects an argument of type ReaderBuilder.
The data field of ReaderBuilder will be always an empty list, so this is also suspicious. I think you probably want to change the Return of ProcBuilder to take an argument MyItem list instead.
However, I think that using custom computation builder for database access doesn't really give you much advantage. You're not creating a "non-standard computation" in some sense. Instead, you probably just want a nice syntax for calling commands & reading data. Using the dynamic operator can make this quite elegant even without computation builders - I wrote an article about this some time ago.
Is it possible to call a method on a returned object using the pipeline infix operator?
Example, I have a .Net class (Class1) with a method (Method1). I can currently code it like this:
let myclass = new Class1()
let val = myclass.Method1()
I know I could also code it as such
let val = new Class1().Method1()
However I would like to do be able to pipeline it (I am using the ? below where I don't know what to do):
new Class1()
|> ?.Method1()
Furthermore, say I had a method which returns an object, and I want to only reference it if that method didn't return null (otherwise bail?)
new Class1()
|> ?.Method1()
|> ?? ?.Method2()
Or to make it clearer, here is some C# code:
public void foo()
{
var myclass = new Class1();
Class2 class2 = myclass.Method1();
if (class2 == null)
{
return;
}
class2.Method2();
}
You can define something similar to your (??) operator fairly easily (but operators can't start with a question mark):
let (~??) f x =
if (x <> null) then
f x
Unfortunately, your pipelined code will need to be a bit more verbose (also, note that you can drop the new keyword for calling constructors):
Class1()
|> fun x -> x.Method1()
Putting it all together:
Class1()
|> fun x -> x.Method1()
|> ~?? (fun x -> x.Method2())
Using a custom operator as 'kvb' suggests is definitely an option. Another approach that you may find interesting in this case is to define your own 'computation expression' that automatically performs the check for null value at every point you specify. The code that uses it would look like this:
open System.Windows.Forms
// this function returns (0) null, or (1) btn whose parent is
// null or (2) button whose parent is not null
let test = function
| 1 -> new Button(Text = "Button")
| 2 -> new Button(Text = "Button", Parent = new Button(Text = "Parent"))
| _ -> null
let res =
safe { let! btn = test(2) // specify number here for testing
// if btn = null, this part of the computation will not execute
// and the computation expression immediately returns null
printfn "Text = %s" btn.Text
let! parent = btn.Parent // safe access to parent
printfn "Parent = %s" parent.Text // will never be null!
return parent }
As you can see, when you want to use a value that can potentially be 'null', you use let! inside the computation expression. The computation expression can be defined so that it immediately returns null if the value is null and runs the rest of the computation otherwise. Here is the code:
type SafeNullBuilder() =
member x.Return(v) = v
member x.Bind(v, f) =
if v = null then null else f(v)
let safe = new SafeNullBuilder()
BTW: If you want to learn more about this, it is very similar to 'Maybe' monad in Haskell (or computation working with F# option type).