Generics with interfaces in F# - f#

In C# one can state that a generic parameter must implement a certain interface like so:
public class Something<T> where T : IComparable
{
...
}
How does one specify this in F#?

Generic constraints use "when" in F#:
type Foo<'a when 'a :> IComparable> =
member x.Bla = 0

Related

F# constructor constraint

Whilst attempting to learn the use of constructor constraints, I was hoping that something like the following was possible.
type Foo<'T when 'T : (new : int -> 'T)> = {Bar: 'T}
But this does not compile, simply returning the error
'new' constraints must take one argument of type 'unit' and return the constructed type
It seems as though the constraint should be called "parameterless constructor constraint" because I cant get any other form beyond this to compile.
type Foo<'T when 'T : (new : unit-> 'T)> = {Bar: 'T}
Can a constructor constraint be used to constrain the generic types constructor to have a specific signature other than unit ?
As noted in the comments, .NET support for constraints is limited and only supports (i) paremeter-less constructors and (ii) implementation of an interface.
F# follows the same restructions for ordinary generic type parameters, but it also has statically resolved type parameters written as ^T, which can have more expressive constraints. Those are not compiled to .NET constraints, but instead, are erased during the compilation, so there are other constraints on those.
An example akin to what you have using static memnber constraints would look something like this:
type Foo<'T> =
{ Bar : 'T }
static member inline Demo< ^S when ^S : (static member Create : int -> ^S)>() =
{ Bar = (^S : (static member Create : int -> ^S) (10)) }
The constrains need to be on an inline member (or inline function), so I'm defining a generic type Foo<'T> which has a static member Demo that can be called with any type that has a Create method taking an int. For example:
type Sample(n:int) =
member x.N = n
static member Create(n:int) = Sample(n)
We can now call Foo.Demo with Sample as the type argument and we get Foo<Sample> back, created using 10 as the initialization value:
let f = Foo<_>.Demo<Sample>()

Finding classes implementing an interface, using reflection, and instantiating them in F#

I am trying to achieve the following:
I have an interface, called IBotCommand and a few classes that implement it. I want to find all these classes, through reflection, instantiate an instance of each and put the result in a dictionary.
the interface is the following:
type IBotCommands =
abstract member Name: unit -> string
abstract member Description: unit -> string
abstract member Help: unit -> string
abstract member Execute: MessageEventArgs -> string[] -> string
and the code:
let t = typeof<IBotCommands>
t.Assembly.GetTypes()
|> Seq.filter (fun x -> x.IsSubclassOf(t))
|> Seq.iter (fun x ->
(
let i = Activator.CreateInstance(x) :> IBotCommands
botCommands.[i.Name] <- i
)
)
the issue I have is with the CreateInstance line. CreateInstance returns an obj type that can't be cast to IBotCommands.
I have the same in C# and it works properly but the C# version is using dynamics:
public static IEnumerable<Type> FindClassSubclassOfType<T>()
{
var a = typeof(T)
.Assembly.GetTypes()
.Where(t => t.IsSubclassOf(typeof(T)))
.Select(t => t);
return a.ToList();
}
var types = ReflectionHelper.FindClassSubclassOfType<BotCommand>();
foreach (var t in types)
{
dynamic c = Activator.CreateInstance(t);
BotCommands[c.Name] = c;
}
how can I get this behavior to work in F#?
can you cast an object to an interface in F#? it's my first time using interfaces in F#
In F#, there is a difference between upcast a :> T and downacst a :?> T.
Upcast is used when the compiler statically knows that a implements an interface T. This is useful if you have a value of a concrete class and want to get a value that has a type of an interface.
Downcast is used when the compiler does not statically know whether a implements an interface. In other words, this means that the cast can fail.
In your case, you need a downcast, because the compiler does not know whether obj implements IBotInterface. All you need to do is to add ?:
let i = Activator.CreateInstance(x) :?> IBotCommands
botCommands.[i.Name] <- i

Implement a C# Interface in F#

I have the following interface in C#
public interface IDog
{
String Bark();
}
I want to create an implementation in F#. I had no problem with this:
type GermanShepherd() =
interface IDog with
member this.Bark() = "Woof"
but when I added a supporting function that is not part of the interface like this:
type GermanShepherd() =
interface IDog with
member this.Bark() = "Woof"
member this.Eat() = "Yummy"
the compiler complained:
Error 1 No abstract or interface member was found that corresponds to this override
Error 2 This value is not a function and cannot be applied*
Is there a way of implementing private/internal functions with a type that implements an interface without those functions being part of the interface? I can't change the interface in my 'real' application b/c there are other projects that implement the interface. None of the examples on MSDN that I found have this particular scenario.
The interface block should only contain functions that are part of the interface, but you can place other functions before the block:
type GermanShepherd() =
member this.Eat() = "Yummy"
interface IDog with
member this.Bark() = "Woof"
If you do not need a public member, then you can go with a private let-bound function:
type GermanShepherd() =
let eat() = "Yummy"
interface IDog with
member this.Bark() = "Woof"
Also note that F# currently only allows explicit interface implementations, which means that you can treat GermanShepherd as IDog, but you won't see IDog members explicitly:
let g = GermanShepherd()
g.Eat() // OK
g.Bark() // Error, interface members are implemented explicitly
let d = g :> IDog // To 'Bark', we need to get 'IDog' first
d.Bark() // OK
One workaround for this is to add the Bark method explicitly as a separate member outside of the interface block. Although there is F# language issue for this too!

Inherit from Seq

I want to create my own custom collection type.
I define my collection as:
type A(collection : seq<string>) =
member this.Collection with get() = collection
interface seq<string> with
member this.GetEnumerator() = this.Collection.GetEnumerator()
But this doesn't compile No implementation was given for 'Collections.IEnumerable.GetEnumerator()
How do i do this?
In F# seq is really just an alias for System.Collections.Generic.IEnumerable<T>. The generic IEnumerable<T> also implements the non-generic IEnumerable and hence your F# type must do so as well.
The easiest way is to just have the non-generic one call into the generic one
type A(collection : seq<string>) =
member this.Collection with get() = collection
interface System.Collections.Generic.IEnumerable<string> with
member this.GetEnumerator() =
this.Collection.GetEnumerator()
interface System.Collections.IEnumerable with
member this.GetEnumerator() =
upcast this.Collection.GetEnumerator()

creating IEnumerable from enumerators in fsharp using anonymous classes

From a class which does not implement Enumerator I can now create one (thks Daniel)
type Bloomberglp.Blpapi.Element with
member this.GetEnumerator() =
(seq { for i in 0 .. this.NumElements - 1 -> this.GetElement(i) }).GetEnumerator()
I am looking to create an IEnumerable wrapper from it
The following works, but is there a better way?
(for instance, a way to not have to specify IEnumerable interface whose implementation can derives from IEnumerable)
member this.ToEnumerableElements():IEnumerable<Element> = {
new IEnumerable<Element> with
member anon.GetEnumerator() :IEnumerator<Element> = this.GetEnumerator()
member anon.GetEnumerator() :IEnumerator = this.GetEnumerator() :> IEnumerator
}
If you want a ToEnumerable method you shouldn't create a GetEnumerator method too. Generally, calling GetEnumerator directly is a code smell anyway.
type Bloomberglp.Blpapi.Element with
member this.ToEnumerable() = Seq.init this.NumElements this.GetElement
With this method in place, you can use the Seq module for most operations and should never have to call GetEnumerator directly.
For example:
elmt.ToEnumerable() |> Seq.iter (printfn "%O")

Resources