Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

multiple constructors and class inheritance in F#

Tags:

f#

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
like image 244
wangzq Avatar asked Dec 01 '14 13:12

wangzq


People also ask

Which constructor is called in multiple inheritance?

For multiple inheritance order of constructor call is, the base class's constructors are called in the order of inheritance and then the derived class's constructor.

Can a class have multiple constructors?

A class can have multiple constructors that assign the fields in different ways. Sometimes it's beneficial to specify every aspect of an object's data by assigning parameters to the fields, but other times it might be appropriate to define only one or a few.

Can a class have multiple constructors with different names?

The technique of having two (or more) constructors in a class is known as constructor overloading. A class can have multiple constructors that differ in the number and/or type of their parameters. It's not, however, possible to have two constructors with the exact same parameters.

How are constructors used in inheritance?

Constructor is automatically called when the object is created. Multiple Inheritance: Multiple Inheritance is a feature of C++ where a class can derive from several(two or more) base classes. The constructors of inherited classes are called in the same order in which they are inherited.


2 Answers

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
like image 138
Marc Sigrist Avatar answered Oct 05 '22 20:10

Marc Sigrist


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.)

like image 45
Vandroiy Avatar answered Oct 05 '22 18:10

Vandroiy