How is F#'s static bound constraints implemented?

随声附和 提交于 2019-12-11 12:18:53

问题


In F#, you can perform black-magic voodoo1 and perform static typed constraints to ensure a function is only called on types that have the member constraints. For example:

module Collection
    let inline init s = 
        let collection = new ^t()
        let add e = (^t : (member Add : 'a -> unit) collection, e)
        Seq.iter add s
        collection

This function can be called where a type that has an Add<'a> that has the signature 'a -> unit.

Usage:

let a:List<_> = Collection.init {1..10}
let b:SynchronizedCollection<_> = Collection.init {1..10}
a |> Seq.iter (fun x -> printf "%A " x)
b |> Seq.iter (fun x -> printf "%A " x)

Output:

1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 

I'm interested in taking advantage of this kind of functionality in a C# application, but have no idea what kind of pitfalls or trouble I can expect with trying this.

In the interest of avoiding the X-Y problem, I have a WCF generated client that is a hacked together manually edited mess. Not using it is not an option for reasons. Many types have member properties with the same name but with different types and no common type, thus my interest in this type of generic constraint.

Is this functionality in F# a viable solution to my problem? How is this implemented? I know C# can do nothing like this...

1Not really, I just don't know how, thus the question.


回答1:


In F#, static member constraints (which is the name of this voodoo) are implemented by inlining the code of the init function each time it is called and generating specialized code for each use.

In general, .NET generic constraints are not rich enough to express member constraints and so this cannot be directly mapped to ordinary .NET generic constraints.

When you write:

let a:List<_> = Collection.init {1..10}
let b:SynchronizedCollection<_> = Collection.init {1..10}

The compiler will basically replace Collection.init with the body of the function and it will replace the call written using static member constraint with a call to the concrete Add method of the concrete type. If the call appears in a generic function where the concrete type cannot be determined, it will not be allowed.

I think you could certainly use F# and static member constraints to simplify working with code where many types share properties without any deeper relationship. However, static member constraints are F# specific and there is no way of defining helper functions using them that could then be called from C#. You would have to write larger portion of the client in F# (and perhaps expose nice clean API that completely hides the underlying types).



来源:https://stackoverflow.com/questions/35166938/how-is-fs-static-bound-constraints-implemented

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!