I did not find a clear answer for this...
What is the F# equivalent of this C# code:
public class SomeClass
{
public virtual SomeMethod([Attribute] Int32 param)
{ }
}
Because there are two different places to put the attribute in F#:
type SomeClass () =
abstract SomeMethod : [<Attribute>] param:Int32 -> Unit
default this.SomeMethod ([<Attribute>] param) = ()
You can put it on both, but the override (default) is the one that counts.
type T =
abstract M : (* [<Out>] this is okay too *) i: byref<int> -> unit
default this.M([<Out>] i) = () //but this one's necessary
Related
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.
I am having difficulty to convert following C# code to F#:
class Foo
{
public Foo() { }
public Foo(string name) { }
}
class Bar : Foo
{
public Bar() : base() { }
public Bar(string name) : base(name) { }
public string Name { get; set; }
}
I first tried following, but it is reporting error
Constructors for the type 'Bar' must directly or indirectly call its
implicit object constructor. Use a call to the implicit object
constructor instead of a record expression.
type Foo() =
new(name:string) = Foo()
type Bar() =
inherit Foo()
new(name:string) = { inherit Foo(name) }
member val Name:string = null with get, set
Then I tried following, but it is now reporting error on the auto property
'member val' definitions are only permitted in types with a primary
constructor. Consider adding arguments to your type definition"
type Foo() =
new(name:string) = Foo()
type Bar =
inherit Foo
new(name:string) = { inherit Foo(name) }
member val Name:string = null with get, set
If you want F# source code who compiles to precisely the same API as given by your C# code, the answer is as follows:
type Foo =
new() = {}
new(name:string) = { }
type Bar =
inherit Foo
[<DefaultValue>]
val mutable private name:string
new() = { inherit Foo() }
new(name) = { inherit Foo(name) }
member x.Name with get() = x.name and set v = x.name <- v
This compiles:
type Foo() =
new(name:string) = Foo()
type Bar(name : string) =
inherit Foo()
new() = Bar(null) // or whatever you want as a default.
member val Name:string = name with get, set
See Constructors (F#) and Inheritance (F#).
Looking at the decompilation, the C# would be (with attributes removed):
public class Bar : Program.Foo {
internal string Name#;
public string Name {
get {
return this.Name#;
}
set {
this.Name# = value;
}
}
public Bar(string name) {
this.Name# = name;
}
public Bar() : this(null) {
}
}
public class Foo {
public Foo() {
}
public Foo(string name) : this() {
}
}
If a class has a parameter list directly after its name (including ()), it has a primary constructor. Using it, any inherit declarations are placed only in this primary constructor, which comes directly after the class declaration and before any member declarations.
It is unclear what you are trying to achieve. The class Foo has a constructor taking a string argument, only to discard it. A (technically) valid, similar pair of classes would be this:
type Foo(name:string) =
member f.NameLength = name.Length
type Bar(initialName) = // WARNING: this will not end well
inherit Foo(initialName)
member val Name:string = initialName with get, set
But this is not sensible code. Foo will keep the initial name even if the name in Bar is changed. Bar.Name.Length returns the current name's length, while Bar.NameLength returns the initial name's length.
To keep the default constructor, one could add new () = Bar(null) (or the equivalent in Foo), but please note that null is considered an interop-only feature. It is not used in F# facing code; if possible, use the appropriate option type or an empty string respectively (depending on whether the string is just empty or doesn't exist at all).
Also, inheriting classes is discouraged in the F# component design guidelines -- for good reason. There are few use cases, but those usually involve a tiny base class and a derived class that is a perfect superset of it. It is far more common to compose types by using one class as a member of another.
I don't know how relevant this is, but here is an example of a class with default constructor and an additional constructor that uses it:
type Text500(text : string) =
do if text.Length > 500 then
invalidArg "text" "Text of this type cannot have a length above 500."
member t.Text = text
new () = Text500("")
This utilizes the primary constructor to verify input and has an additional, parameterless constructor that uses an empty string. (I'm not sure if the additional constructor would be useful in actual applications.)
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)
I would like to get the benefits of CSLA from F#, but I am having trouble with inheritance. Here is the ProjectTracker ResourceInfo class. Can someone please show how to do it in F#?
using Csla;
using System;
using Csla.Serialization;
namespace ProjectTracker.Library
{
[Serializable()]
public class ResourceInfo : ReadOnlyBase<ResourceInfo>
{
private static PropertyInfo<int> IdProperty = RegisterProperty<int>(c => c.Id);
public int Id
{
get { return GetProperty(IdProperty); }
private set { LoadProperty(IdProperty, value); }
}
private static PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
public string Name
{
get { return GetProperty(NameProperty); }
private set { LoadProperty(NameProperty, value); }
}
public override string ToString()
{
return Name;
}
internal ResourceInfo(int id, string lastname, string firstname)
{
Id = id;
Name = string.Format("{0}, {1}", lastname, firstname);
}
}
}
The solution by jpalmer shows the general structure, but I think there are a couple of problems. I don't have experience with CSLA, so I haven't tried running this, but I downloaded the DLL and tried type-checking the sample.
First of all, the RegisterProperty method does not take a lambda function, but an expression (and uses it to get information about the property using reflection). To get this working, you need to write a helper using F# quotations:
open Microsoft.FSharp.Quotations
open System.Linq.Expressions
let prop (q:Expr<'T -> 'R>) =
match q with
| Patterns.Lambda(v, Patterns.PropertyGet(_, pi, _)) ->
let v = Expression.Variable(v.Type)
Expression.Lambda<Func<'T, 'R>>
(Expression.Property(v, pi), [v])
| _ -> failwith "wrong quotation"
This turns a quoted F# lambda function to a C# expression tree in the expected format. You can then call RegisterProperty with something like prop <# fun (a:Foo) -> a.Bar #> as an argument.
I also see that IdProperty should be static, which can be done using static let (if it is private). The following should be the right way of defining type with one property:
[<Serializable>]
type ResourceInfo internal (id:int, lastname:string, firstname:string) as this =
inherit ReadOnlyBase<ResourceInfo>()
// Code executed as part of the constructor
do this.Id <- id
static let IdProperty =
ReadOnlyBase<ResourceInfo>.RegisterProperty<int>
(prop <# fun (r:ResourceInfo) -> r.Id #>)
member x.Id
with get() = x.GetProperty(IdProperty) |> unbox
and set(v) = x.LoadProperty(IdProperty, v)
I generally quite like the style when you write accessibility modifiers directly in your code (as in C#), so I annotated the constructor with internal as in your code. I also added constructor body that sets the Id property when the object is created.
This should be close - the standard way to do the access control in F# is to use signature files, which I left out
module ProjectTracker.Library
open Csla;
open System;
open Csla.Serialization;
[<Serializable>]
type ResourceInfo(id, lastname, firstname) =
inherit ReadOnlyBase<ResourceInfo>()
Id <- id
Name <- sprintf "%s, %s" lastname firstname
let IdProperty = RegisterProperty<int>(fun c -> c.Id);
member x.Id with get() = GetProperty(IdProperty) and set(v) = LoadProperty(IdProperty, v)
//skipped a property here - similar to above
override x.ToString() = Name
#Tomas
I am honored by your reply and touched by your effort to do so--downloading CSLA, identifying the expression as a problem, and creating a non-obvious way to deal with it. I love your book, Real-World Functional Programming, which goes beyond language features and into how to apply them to important real-world problems.
CSLA was out before C# had lambdas, so I went back to see how Lhotka then used RegisterProperty. If other users want to avoid expressions, it looks like this works, too:
static let IdProperty =
ReadOnlyBase<ResourceInfo>.RegisterProperty
(typeof<ResourceInfo>, new PropertyInfo<int>("Id"))
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)