Im in the middle of porting my C# code to a F# library. I have the following interfaces/classes in my C# library:
public interface IMatch<out T> where T : IGame
{
IEnumerable<T> Games { get; }
}
public interface IGame
{
string Name { get; }
}
public class SoccerMatch : IMatch<SoccerGame>
{
public SoccerMatch(IEnumerable<SoccerGame> games)
{
Games = games;
}
public IEnumerable<SoccerGame> Games { get; }
}
public class SoccerGame : IGame
{
public SoccerGame(string name)
{
Name = name;
}
public string Name { get; }
}
I have tried to port this to F#, this is what I've come up with:
type IGame =
abstract member Name: string with get
type IMatch<'T when 'T :> IGame> =
abstract member Games: IEnumerable<'T> with get
type SoccerGame =
{Name: string}
interface IGame with
member this.Name with get() = this.Name
type SoccerMatch =
{ Games: IEnumerable<SoccerGame>}
interface IMatch<SoccerGame> with
member this.Games: IEnumerable<SoccerGame> = this.Games
The problem is, I need to call this F# library from my C# application. Before, when using the C# classes, I could do the following:
var match= new SoccerMatch(new List<SoccerGame>());
IMatch<IGame> interfaceType = match;
But when I try to do the same with my F# library like this:
var match = new SoccerMatch(new List<SoccerGame>());
IMatch<IGame> interfaceType = match;
I get the following error: Error CS0029 Cannot implicitly convert type 'FSharp.SoccerMatch' to 'FSharp.IMatch'
Im thinking that something must be wrong in my F# implementation(obviously), but what?
Your F# type doesn't behave the same as C# one because it's not the same as C# one. C# one has T
parameter declared as "out":
public interface IMatch<out T> where T : IGame
That out
means type parameter T
is covariant, and that's exactly what allows implicit conversion from SoccerMatch
(which is IMatch<SoccerGame>
) to IMatch<IGame>
.
However, F# does not support covariance \ contravariance in generic interfaces, as far as I know. It has been suggested by years, but issue is still open. So your F# interface is analog of this C# one:
public interface IMatch <T> where T : IGame
{
IEnumerable<T> Games { get; }
}
Which will produce the same compile-time error.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With