Given an F# type:
type Foo() =
member this.Prop with get() = ()
interface IDisposable with
member this.Dispose() = ()
In C#, I create the object, but I can't call Dispose():
var x = new Foo();
x.Dispose(); // compile error, x does not contain a definition of Dispose
However, I can write:
((IDisposable)x).Dispose(); // works, but I don't like the cast
Is there any way to avoid the cast in C#? Is this related to the way F# doesn't automatically let you call .Dispose() on the Foo type from within F#?
Interface implementations in F# are explicit by default. Hence the methods are not visible unless seen from the type converted to the interface (some form of casting).
To work around this expose an instance method which has the same signature as the interface version. Then have the interface on forward to the instance function. For example
type Foo() =
member this.Prop with get() = ()
member this.Dispose() = ()
interface IDisposable with
member this.Dispose() = this.Dispose()
How about, for this particular interface:
using (var x = new Foo()) {
...
}
Related
In C#, I have the following interface definition:
using System.Collections;
public interface ISuggestionProvider
{
#region Public Methods
IEnumerable GetSuggestions(string filter);
#endregion Public Methods
}
In F#, I have tried doing this:
type ISuggestionProvider =
abstract member GetSuggestions: string -> seq<'T>
type DiagnosisProvider () =
interface ISuggestionProvider with
member this.GetSuggestions s =[ "one"; "two"; "three"] |> Seq.cast
But when this is read back into C#, I get:
public IEnumerable<T> GetSuggestions<T>(string value)
{
throw new NotImplementedException();
}
What I need is it to be read back as:
public System.Collections.IEnumerable GetSuggestions(string filter)
{
return _method(filter);
}
In short, how do I return an untyped IEnumerable instead of IEnumerable<'T> ???
Thanks in advance for any help.
You need to define your interface an implementation in terms of IEnumerable, not seq<'T>. F# sequences are generic, so if you need the non-generic one you can't use sequences.
open System.Collections
type ISuggestionProvider =
abstract member GetSuggestions: string -> IEnumerable
type DiagnosisProvider () =
interface ISuggestionProvider with
member this.GetSuggestions s =
[ "one"; "two"; "three"]
:> IEnumerable
In C# you can annotate methods with async like this:
class Foo
{
public async void Bar()
{
}
}
This is different to an F# async; I believe that in F# these are called tasks.
So, how do I write a C#-style async member function in F#?
// Not real code
type Foo () =
member async this.Bar () =
()
The solution must compile to IL with the same public interface as the C# above.
A C# async method is just a method returning a value of type Task<T>. The C# compiler uses the async keyword to determine that you are allowed to use await inside the code block, but as far as I know, it is not represented in any way in the compiled code.
You say "the solution must compile to the same IL" - that's not going to be easily possible, because F# implements asynchronous operations differently. However, you can get it to compile to IL that has the same public interface using something like this:
type Foo () =
member this.Bar () = Async.StartAsTask <| async {
// yadda yadda
}
The asynchronous operation is implemented using standard F# async workflow, so under the cover, this creates an F# Async<T>, but the Async.StartAsTask operation turns that into a Task<T> type, which is what C# expects.
EDIT: Another alternative is to use the TaskBuilder computation expression, which lets you directly create .NET tasks using something like this:
type Foo () =
member this.Bar () = task {
// yadda yadda
}
Async.StartAsTask should do it. This will give you Threading.Tasks.Task<'a>
let bar =
async{
return ()
}
|>Async.StartAsTask
I wrote some code like
type internal IMyInterface =
abstract member Method1 : unit -> unit
type Class1() =
member this.Y() =
(this :> IMyInterface).Method1()
interface IMyInterface with
member this.Method1() = ()
Note that the public type Class1 implements an internal interface IMyInterface, it compiles fine. In the generated MSIL, "Method1" was shown as private. This is similar to explicit interfaces in C#.
However, when I change the code a bit to
type internal Foo() =
member x.Value = "Foo"
type internal IMyInterface =
abstract member Method1 : Foo -> unit
type Class1() =
member this.Y() =
let v = Foo()
(this :> IMyInterface).Method1(v)
interface IMyInterface with
member this.Method1(v : Foo) = ()
This type the interface method "Method1" takes an internal type "Foo" as parameter. This time, it does not compile with an error
The type 'Foo' is less accessible than the value, member or type 'override Class1.Method1 : v:Foo -> unit' it is used in
I have trouble to decipher this error message and find a fix for it. In C#, I can write the following code that compiles fine
internal class Foo
{
string Value { get; set; }
}
internal interface IMyInterface
{
void Method1(Foo v);
}
public class Class1 : IMyInterface
{
public void Y()
{
var v = new Foo();
(this as IMyInterface).Method1(v);
}
void IMyInterface.Method1(Foo v)
{
throw new NotImplementedException();
}
}
Any idea about the F# compiler error and how to work around it?
BTW: this may not be the right way/pattern to use interface anyway, I'm just curious on the language syntax
As it was pointed out at Patrick's comment, this issue was logged as a bug of Visual F#. Currently it's included in F# 4.0 Update 3 milestone.
In C#, I can implement a generic interface twice on one class, using two different type-parameters:
interface IFoo<T> { void Foo(T x); }
class Bar : IFoo<int>, IFoo<float>
{
public void Foo(int x) { }
public void Foo(float y) { }
}
I would like to do the same thing in F#:
type IFoo<'a> = abstract member Foo : 'a -> unit
type Bar() =
interface IFoo<int> with
[<OverloadID("int")>]
member this.Foo x = ()
interface IFoo<float> with
[<OverloadID("float")>]
member this.Foo x = ()
But it gives a compiler error:
This type implements or inherits the same interface at different generic instantiations 'IFoo<float>' and 'IFoo<int>'. This is not permitted in this version of F#.
I can't find any discussion of this issue on the web. Is such use frowned upon for some reason? Are there plans to allow this in an upcoming release of F#?
Right now I don't know of plans to allow this.. The feature has been planned and is, at least partially (see comments) implemented in F# 4.0.
I think the only reasons its currently disallowed are that it's non-trivial to implement (especially with F# type inference), and it rarely arises in practice (I only recall one customer ever asking about this).
Given an infinite amount of time and resources, I think this would be allowed (I can imagine this being added to a future version of the language), but right now it does not seem like this is a feature worth the effort of supporting. (If you know a strong motivating case, please mail fsbugs#microsoft.com.)
EDIT
As an experiment for the curious, I wrote this C#:
public interface IG<T>
{
void F(T x);
}
public class CIG : IG<int>, IG<string>
{
public void F(int x) { Console.WriteLine("int"); }
public void F(string x) { Console.WriteLine("str"); }
}
and referenced it from F# (with comments suggesting the results)
let cig = new CIG()
let idunno = cig :> IG<_> // type IG<int>, guess just picks 'first' interface?
let ii = cig :> IG<int> // works
ii.F(42) // prints "int"
let is = cig :> IG<string> // works
is.F("foo") // prints "str"
so this is what typically happens on this 'boundary' stuff with F# - F# can consume this stuff ok, even if you can't author the same stuff from within the language.
There is a reasonable although not elegant way to do it, create a new type for each interface here is an example of consuming multiple events from an ESB (nSvcBus) which requires that each event corresponds to an implemented interface. The first type below contains the generic 'handler' code, the other types just implement the interface and call to the generic handler
type public nSvcBusEvents() =
member this.HandleEvents(msg:IEvent) = ()
//handle messages ie: let json = JsonConvert.SerializeObject(msg)
type public ActionLoggedHandler() =
interface IHandleMessages<Events.ActionLoggedEvent> with
member this.Handle(msg : ActionLoggedEvent) =
nSvcBusEvents().HandleEvents(msg)
type public ActionCompletedHandler() =
interface IHandleMessages<Events.ActionCompletedHandler> with
member this.Handle(msg : ActionCompletedHandler) =
nSvcBusEvents().HandleEvents(msg)
type public ActionFailedHandler() =
interface IHandleMessages<Events.ActionFailedHandler> with
member this.Handle(msg : ActionFailedHandler) =
nSvcBusEvents().HandleEvents(msg)
In C#, I can implement a generic interface twice on one class, using two different type-parameters:
interface IFoo<T> { void Foo(T x); }
class Bar : IFoo<int>, IFoo<float>
{
public void Foo(int x) { }
public void Foo(float y) { }
}
I would like to do the same thing in F#:
type IFoo<'a> = abstract member Foo : 'a -> unit
type Bar() =
interface IFoo<int> with
[<OverloadID("int")>]
member this.Foo x = ()
interface IFoo<float> with
[<OverloadID("float")>]
member this.Foo x = ()
But it gives a compiler error:
This type implements or inherits the same interface at different generic instantiations 'IFoo<float>' and 'IFoo<int>'. This is not permitted in this version of F#.
I can't find any discussion of this issue on the web. Is such use frowned upon for some reason? Are there plans to allow this in an upcoming release of F#?
Right now I don't know of plans to allow this.. The feature has been planned and is, at least partially (see comments) implemented in F# 4.0.
I think the only reasons its currently disallowed are that it's non-trivial to implement (especially with F# type inference), and it rarely arises in practice (I only recall one customer ever asking about this).
Given an infinite amount of time and resources, I think this would be allowed (I can imagine this being added to a future version of the language), but right now it does not seem like this is a feature worth the effort of supporting. (If you know a strong motivating case, please mail fsbugs#microsoft.com.)
EDIT
As an experiment for the curious, I wrote this C#:
public interface IG<T>
{
void F(T x);
}
public class CIG : IG<int>, IG<string>
{
public void F(int x) { Console.WriteLine("int"); }
public void F(string x) { Console.WriteLine("str"); }
}
and referenced it from F# (with comments suggesting the results)
let cig = new CIG()
let idunno = cig :> IG<_> // type IG<int>, guess just picks 'first' interface?
let ii = cig :> IG<int> // works
ii.F(42) // prints "int"
let is = cig :> IG<string> // works
is.F("foo") // prints "str"
so this is what typically happens on this 'boundary' stuff with F# - F# can consume this stuff ok, even if you can't author the same stuff from within the language.
There is a reasonable although not elegant way to do it, create a new type for each interface here is an example of consuming multiple events from an ESB (nSvcBus) which requires that each event corresponds to an implemented interface. The first type below contains the generic 'handler' code, the other types just implement the interface and call to the generic handler
type public nSvcBusEvents() =
member this.HandleEvents(msg:IEvent) = ()
//handle messages ie: let json = JsonConvert.SerializeObject(msg)
type public ActionLoggedHandler() =
interface IHandleMessages<Events.ActionLoggedEvent> with
member this.Handle(msg : ActionLoggedEvent) =
nSvcBusEvents().HandleEvents(msg)
type public ActionCompletedHandler() =
interface IHandleMessages<Events.ActionCompletedHandler> with
member this.Handle(msg : ActionCompletedHandler) =
nSvcBusEvents().HandleEvents(msg)
type public ActionFailedHandler() =
interface IHandleMessages<Events.ActionFailedHandler> with
member this.Handle(msg : ActionFailedHandler) =
nSvcBusEvents().HandleEvents(msg)