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>()
Related
I have defined an interface in F# with an overloaded method. As per compiler request, the overload uses tupled arguments instead of curried ones:
type IInterface =
abstract member Do : (int * string) -> unit
abstract member Do : int -> unit
I then create a class which implements the interface:
type ImplementingClass =
interface IInterface with
member this.Do (i, s) = ()
member this.Do i = ()
However, doing so yields the compiler error for the first of both methods: "This override takes a different number of arguments to the corresponding abstract member"
What am I doing wrong here?
There is a subtle difference between the following two:
abstract member Do : int * string -> unit
abstract member Do : (int * string) -> unit
If you add the parentheses, you're saying that the parameter is a tuple and the compiler should produce a method taking Tuple<int, string>. Without parentheses, the method will be compiled as taking two parameters. Most of the time, this is hidden and you can ignore it - but sadly, not always.
So, you can either change your interface definition to use ordinary "two-parameter" method (this would be my preferred method - you can still call the method with tuple as an argument and looks nicer in the .NET/C# view):
type IInterface =
abstract member Do : int * string -> unit
abstract member Do : int -> unit
type ImplementingClass =
interface IInterface with
member this.Do (i, s) = ()
member this.Do i = ()
Or you can implement the interface as it is:
type ImplementingClass =
interface IInterface with
member this.Do((i:int, s:string)) = ()
member this.Do(i:int) = ()
Sadly, this is a bit ugly - you need the type annotations so that the compiler can unambiguously decide which method you're implementing.
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!
Is it possible to create static member indexed properties in F#? MSDN show them only for instance members, however, I'm able to define the following class:
type ObjWithStaticProperty =
static member StaticProperty
with get () = 3
and set (value:int) = ()
static member StaticPropertyIndexed1
with get (x:int) = 3
and set (x:int) (value:int) = ()
static member StaticPropertyIndexed2
with get (x:int,y:int) = 3
and set (x:int,y:int) (value:int) = ()
//Type signature given by FSI:
type ObjWithStaticProperty =
class
static member StaticProperty : int
static member StaticPropertyIndexed1 : x:int -> int with get
static member StaticPropertyIndexed2 : x:int * y:int -> int with get
static member StaticProperty : int with set
static member StaticPropertyIndexed1 : x:int -> int with set
static member StaticPropertyIndexed2 : x:int * y:int -> int with set
end
But when I try to use one, I get an error:
> ObjWithStaticProperty.StaticPropertyIndexed2.[1,2] <- 3;;
ObjWithStaticProperty.StaticPropertyIndexed2.[1,2] <- 3;;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error FS1187: An indexer property must be given at least one argument
I tried a few different syntax variations and none worked. Also weird is that when I hover over set in VS2010 for one of the definitions in the type, I get info about ExtraTopLevelOperators.set.
If you wanted to recover the Type.Prop.[args] notation, then you can define a simple object to represent an indexable property with the Item property:
type IndexedProperty<'I, 'T>(getter, setter) =
member x.Item
with get (a:'I) : 'T = getter a
and set (a:'I) (v:'T) : unit = setter a v
type ObjWithStaticProperty =
static member StaticPropertyIndexed1 =
IndexedProperty((fun x -> 3), (fun x v -> ()))
ObjWithStaticProperty.StaticPropertyIndexed1.[0]
This returns a new instance of IndexedProperty every time, so it may be better to cache it. Anyway, I think this is quite nice trick and you can encapsulate some additional behavior into the property type.
A digression: I think that an elegant extension to F# would be to have first-class properties just like it has first-class events. (You could for example create properties that automatically support INotifyPropertyChange with just one line of code)
I believe that you call indexed properties using a different syntax (whether instance or static):
ObjWithStaticProperty.StaticPropertyIndexed2(1,2) <- 3
The only semi-exception to this is that an Item property on an instance x can be called via x.[...] (that is, Item is omitted and brackets are used around the arguments).
I have an type that is implementing IEnumerable<T> interface, all is ok:
open System
type Bar() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () = null
But things goes wrong if type inherits IEnumerable interface implementation via the base type:
open System
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
type Bar() =
inherit Foo()
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () = null
Code above produces the type inference errors:
The member 'GetEnumerator<'a0 when 'a0 : null> : unit -> 'a0 when 'a0 : null' does not have the correct type to override any given virtual method
The member 'GetEnumerator<'a0 when 'a0 : null> : unit -> 'a0 when 'a0 : null' does not have the correct number of method type parameters. The required signature is 'GetEnumerator : unit -> Collections.Generic.IEnumerator<int>'.
Am I doing something wrong or this is an F# compiler bug?
Microsoft (R) F# 2.0 Interactive build 4.0.30319.1
Update more canonical example:
type IFoo = abstract Bar : obj list
type IFoo<'a> = abstract Bar : 'a list
inherit IFoo
/* ok */
type Foo = interface IFoo with member x.Bar = []
interface IFoo<Foo> with member x.Bar = []
/* fail */
type FooBase = interface IFoo with member x.Bar = []
type FooDerived = interface IFoo<Foo> with member x.Bar = [] // <---
inherit FooBase
/*
error FS0017: The member 'get_Bar : unit -> 'a list' does not
have the correct type to override any given virtual method.
*/
The compiler cannot infer the correct type from your "null"-implementation. Try
open System
type Foo() =
interface Collections.IEnumerable with
member x.GetEnumerator () = null
type Bar() =
inherit Foo()
interface Collections.Generic.IEnumerable<int> with
member x.GetEnumerator () : Collections.Generic.IEnumerator<int> = null
UPDATE:
The reason is, that the type of the GetEnumerator method implemented by the Bar type is ambigous as IEnumerable<'a> implements/inherits the non-generic IEnumerable which also specifies a (non-generic) GetEnumerator method. So, how should the compiler infer, which method exactly you are trying to implement if all he gets is null? Therefore we need a type annotation in this case.
This is not a bug, this is just an type inference fail because of F# may implement inherited interface members in the derived interface implementation declaration:
type IA = abstract A : int
type IB = inherit IA
type IC = inherit IB
type Baz =
interface IC with
member x.A = 1
So in my example I should specify the correct return type explicitly because member x.GetEnumerator() in derived Bar type may match both IEnumerable.GetEnumerator() and IEnumerable<T>.GetEnumerator().
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