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.)
Related
I would like to make a generic class which only accepts Lists as a type parameter. But I also want the type parameter of the List. Something like this:
class MyClass<L extends List<T>> {
T foo() {
// ....
}
}
The problem is that that does not work. T is not found. But this does:
class MyClass<L extends List<T>, T> {
T foo() {
// ....
}
}
My only issue with this is that I have to always pass in the extra parameter T which should be inferred from the List type.
var instance = MyClass<List<int>>();
var instance = MyClass<List<int>, int>(); // Extra int kind of redundant
Is there any workaround to this?
The solution is similar to the one provided in this question (the same problem, but in Java): basically, you can't do that in Dart. What you can do is
create a new subclass:
class MyClass2<T> extends MyClass<List<T>, T> { ... }
or
create a factory method:
class MyClass<L extends List<T>, T> {
static MyClass<List<T>, T> fromList<T>(List<T> list) {
return MyClass(...);
}
}
I'm working on a library, and I have a implementation pattern users are required to follow:
class MyView extends LibView {
static Foo f = Foo();
#override
void render(){
use(f); // f should be static, otherwise things not work correctly
}
}
I would like to tell the compiler that, if someone ever does this, it's incorrect:
class MyView {
Foo f = Foo(); // Error: Foo can only be used in Static field.
...
}
Anyone know if this is possible? I find it really hard to find good docs on these sorta of language details when it comes to dart.
[EDIT] Since the "why" question always comes up, imagine something like:
class ViewState{
Map<int, Object> props = {};
}
ViewState _state = ViewState();
class View {
View(this.state);
ViewState state;
static int _key1 = getRandomInt();
void render(){
print(state(_key1))
}
}
// These should both print the same value off of state since the 'random' int is cached
View(_state);
View(_state);
If the key's were not static, everything would compile fine, but they would not print the same results.
What you properly need are a singleton which can be created in different ways in Dart. One way is to use a factory constructor like this:
class Foo {
static final Foo _instance = Foo._();
factory Foo() => _instance;
// Private constructor only used internally
Foo._();
}
void main() {
final a = Foo();
final b = Foo();
print(identical(a, b)); // true
}
By doing it like this, there will only be one instance of Foo which are then shared each time an instance are asked for. The instance are also first created the first time it is asked for since static variables in Dart are lazy and only initialized when needed.
I just want to do the functional equivalent of
int someUniqueKey = 0, or MyViewEnums.someUniqueKey but do it with a typed object rather than a int/enym, like: Object<Foo> someUniqueKey = Object<Foo>(). In order for this to work with Objects, it needs to be static. It's similar to how int someUniqueKey = random.nextInt(9999) would have to be static in order to be used as a key that all instances could share. That way keys are auto-managed and unique, and people don't need to assign int's, strings, or whatever. It also has the advantage of letting me use the type later for compile time checks.
bool prop = getPropFromRef(_prop1Ref); //Will throw error prop1Ref is not Ref<bool>
I think I've figured out something that does the trick using darts package-level methods.
class Ref<T> {}
// Re-use existing ref if it already exists
Ref<T> getRef<T>(Ref<T> o) => o ?? Ref<T>();
class RefView {}
// In some other package/file:
class MyView extends RefView {
static Ref<bool> prop1Ref = getRef(prop1Ref);
static Ref<int> prop2Ref = getRef(prop2Ref);
}
This will make sure that prop1 and prop2 have the same values across all instances of MyView and it will throw an error if these are not static (since you can not pass an instance field before Constructor)
This still has the downside of a potential hard to spot error:
class MyView extends RefView {
static Ref<bool> prop1 = getRef(prop1);
static Ref<bool> prop2 = getRef(prop1); // passing prop1 to prop2's getRef, and they have the same<T>, compiler will miss it
}
But I think it might be preferable than having this potential error:
class MyView extends RefView {
//Both of these will fail silently, keys will change for each instance of MyView
Ref<bool> prop1 = getRef(prop1);
Ref<bool> prop2 = getRef(prop2);
}
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 have a code snippet here but i don't understand the use of "new (code)" in it.
type Product (code:string, price:float) =
let isFree = price=0.0
new (code) = Product(code,0.0)
member this.Code = code
member this.IsFree = isFree
Specifically why the need to enclose the "code" variable inside brackets.
That's a constructor. From MSDN: Classes (F#) (see section 'Constructors'):
You can add additional constructors by using the new keyword to add a member, as follows:
new (argument-list) = constructor-body
In your example, the Product type has one default constructor which accepts code and price, and one additional constructor that takes only code and applies the default constructor with 0.0 for price. In this case, the parentheses around code are not strictly required, and the code would compile just the same without it, although it would be required if you want constructor that takes zero parameters or more than one parameter.
The equivalent C# would be something like this:
public class Product
{
private string code;
private bool isFree;
public Product(string code, double price) {
this.code = code;
this.isFree = price == 0.0;
}
public Product(string code) : this(code, 0.0) { }
public string Code { get { return this.code; } }
public float IsFree { get { return this.isFree; } }
}
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"))