Multiple constructors and properties

Viewed 719

I get the next errors with my source:

  1. 'Name' hasn't value
  2. You should call an alternate constructor

Then, how do I the next class in F#?

type Person = class
    member val Name: string
    member val Age: int option = None

    new() = { Name = "Anonymous" }
    new(name) = { Name = name }
    new(name, age: int) = { Name = name; Age = age }

    static member Hello =
            printfn "Hello, %O" Name
    end

Edit

Based on the @user2088029 answer in this post and the @kvb answer in Object initializer + property initializer (from C# to F#), I have created the next source, which has I want get. The problem is "Person(name, Age = age)" indicates error with "No accessible member or object constructor named 'Person' takes 1 argument".

type Person(name) = 
    member this.Name: string = name
    member this.Age: int option = None //with get,set

    new() = Person("Anonymous")
    new(name, age: int) = Person(name, Age = age)

    member this.Hello =
        printfn "Hello, %O" this.Name

Usage:

let person = Person("Alex", Option = Some 25)
2 Answers
type Person(name : string,age : int option) = 
   new() = Person("Anonymous")
   new(name) = Person(name,None)
   new(name, age: int) = Person(name, Some age)
   member this.Name : string       = name
   member this.Age : int option    = age

   member this.Hello() =
        printfn "Hello, %O" this.Name

I'm not completely sure what you want to do, F# isn't my first language, and I possibly wouldn't write code like this (I personally don't like multiple constuctors)...but anyway

the primary constructor is put after the type name. then you don't need "class" and "end"

the primary constructor does 2 things

I) it defines a static method for creating new objects/values

ii) it defines field/attributes of class

you then have the other constructors....

I assume you want Name and Age to be instance methods on the class Person?..so they needs to be prefixed with an object variable, "this" seems a sensible name for OOers.

your static method doesn't work because if it's static it has no variable to represent a person, so I've implemented it as an instance method

I'm not too sure why the "class/end" construct exists, I suspect it may be because you can create "struct/end" structures, and these don't have a constructor, but I have almost never seen "class/end" construct used anywhere outside of the section in text books that describe the syntax.

In the revised code snippet, there are two problems:

  • Your Age property is read-only so it does not have a setter
  • Your initializer in the constructor taking name and age is invalid - there are fairly strict restrictions in F# on how constructors should look

You can fix the former by turning Age into val property with get, set and you can fix the latter by using a (somewhat strange) syntax for calling a base constructor, followed by additional operations. The following works:

type Person(name) = 
    member this.Name: string = name
    member val Age = None with get, set

    new() = Person("Anonymous")
    new(name, age: int) as this = Person(name) then this.Age <- Some age

    member this.Hello =
        printfn "Hello, %O" this.Name

That said, the solution by @user2088029 which makes the constructor with both parameters the primary one is much nicer and I'd recommend using that instead!

Related