2

Given

type A() = 
 member val Prop: int = 0 with get, set

There are multiple ways to create an instance

let a0 = A() // Prop = 0
let a1 = A(Prop = 1)
let a2 = A()
a2.Prop <- 2

Now we want to enhance our class and allow passing the prop value in the constructor, but without losing the parameterless constructor we already have

type A1() = 
 member val Prop: int = 0 with get, set
 new(prop: int) = A1(Prop = prop) //Error

However this is an error

This is not a valid object construction expression. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor.

which doesn't seem correct as the new constructor is actually calling an alternate constructor.

There are alternatives/workarounds to achieve the result, for example:

type A2() = 
 member val Prop: int = 0 with get, set
 static member Create(prop: int) = A(Prop = prop)
let a21 = A2.Create(1)
type A3(?prop: int) as this = 
 do if prop.IsSome then this.Prop <- prop.Value
 member val Prop: int = 0 with get, set
let a31 = A3(1)

however the A1 version seems the cleanest and there are no apparent reasons why it cannot be valid (it is very similar to the A2 static member)

Can someone explain why the A1 syntax cannot be valid?

asked Jun 3, 2022 at 7:34

2 Answers 2

4

The primary constructor of your object should generally take all the parameters required for constructing a valid object. As a general rule I'd make the secondary constructor parameterless and the primary take all the parameters you care about.

If you must have a parameterless primary constructor but still want to assign properties in secondary constructors you can use the then keyword for side-effectful construction.

type A1() = 
 member val Prop: int = 0 with get, set
 new(prop: int) as this = 
 A1()
 then 
 this.Prop <- prop
answered Jun 3, 2022 at 10:57
1
  • Ah, I overlooked the "then" keyword/syntax. Then the strategy with private constructors isn't as useful as I thought, but maybe in some cases. Commented Jun 4, 2022 at 18:04
2

I don't know if it cannot be valid if somebody decides the compiler should handle it, but I thought you might be interested in how we normally solve this case.

type A4(prop: int) =
 member val Prop = prop with get, set
 new() = A4(0)
let a4a = A4() // 0
let a4b = A4(3) // 3
let a4c = A4(Prop=7) // 7

Following this, it's useful to know how to make private constructors.

type A4 private (prop: int) =
 member val Prop = prop with get, set
 private new () = A4(0)

This example is of course rather useless code, but it shows where to put the private keyword. As you probably already understand, you can use one or more private constructors, typically with many parameters, as helpers for public constructors that have fewer parameters.

answered Jun 3, 2022 at 9:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.