fsharp / fslang-suggestions

The place to make suggestions, discuss and vote on F# language and core library features
340 stars 21 forks source link

Allow the initialization of explicit fields when using a primary constructor #1302

Open trevorgray opened 9 months ago

trevorgray commented 9 months ago

I propose we allow the initialization of explicit fields when using a primary constructor.

Currently in order to initialize explicit fields, a non-primary constructor is required:

// Explicit fields assigned in constructor
type MyClass =
    val mutable a: int
    val mutable b: int
    new(a0, b0) = { a = a0; b = b0; }

// Explicit fields assigned when using primary constructor
type MyClass2() as this =
    [<DefaultValue>]
    val mutable a: int

    [<DefaultValue>]
    val mutable b: int

    do
        this.a <- 5
        this.b <- 6

// Explicit fields assigned when using let bindings
type MyClass3 private (c0: int) =
    [<DefaultValue>]
    val mutable a: int

    [<DefaultValue>]
    val mutable b: int

    let c = c0

    new(a0, b0, c0) as this =
        MyClass3(c0)
        then
            this.a <- a0
            this.b <- b0

[<Struct>]
type Struct1 =
    val mutable a: int
    new (a0) = { a = a0 }

This proposal is to update the language to allow explicit fields to be initialized when using a primary constructor so that the following is possible:

type MyClass(a0: int, b0: int) =
    val mutable a = a0
    val mutable b = b0

type MyClass2() =
    val mutable a = 5
    val mutable b = 6

type MyClass3(a0: int, b0: int, c0: int) =
    val mutable a = a0
    val mutable b = b0
    let c = c0

// Not possible today: A type that has a non-mutable explicit field and a let binding.
type MyClass4(a0: int, c0: int) =
    val a = a0
    let c = c0

// Same as today. Struct cannot have primary non-parameterless constructor so a non-primary constructor must be used.
[<Struct>]
type Struct1 =
    val mutable a: int
    new (a0) = { a = a0 }

// Not possible today: Parameterless struct constructor.
[<Struct>]
type Struct2 =
    val mutable a: int
    new () = { a = 5 }

// Alternatively using new inline initialization.
[<Struct>]
type Struct2() =
    val mutable a = 5

Related C# feature for parameterless stuct constructors:

Pros and Cons

The advantages of making this adjustment to F# are ...

The disadvantages of making this adjustment to F# are ...

Extra information

Estimated cost (XS, S, M, L, XL, XXL):

Related suggestions: (put links to related suggestions here)

Affidavit (please submit!)

Please tick these items by placing a cross in the box:

Please tick all that apply:

For Readers

If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.

Happypig375 commented 9 months ago

Would let mutable public be possible?

trevorgray commented 9 months ago

That could be an alternative to this. However, currently let bindings in types are always private and do not allow an access modifier to be applied whereas explicit fields can have any access modifier.

bartelink commented 9 months ago

Might be useful to reference the { inherit construct in defining the requirement