F # inheritable with multiple constructor syntax

I have this F# class

module File1

open System
open System.Collections.Generic

type TimeRangeList<'e>(getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) as this =
inherit List<'e>()
//inherit List<'e>(getter(defaultArg maybe_tTo DateTime.Now, defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0))))

let tTo = defaultArg maybe_tTo DateTime.Now
let tFrom = defaultArg maybe_tFrom (tTo.AddDays(-1.0))
do this.AddRange(getter(tFrom, tTo))

Now I want to add a constructor and use the syntax from here

type TimeRangeList<'e> = 
inherit List<'e>
val tFrom: DateTime
val tTo: DateTime
new (getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) = {
inherit List<'e>()
//inherit List<'e>(defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.N ow).AddDays(-1.0)), getter(defaultArg maybe_tTo DateTime.Now))

tTo = defaultArg maybe_tTo DateTime.Now
tFrom = defaultArg maybe_tFrom (tTo.AddDays(-1.0) ) //tTo undefined
//tFrom = defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0))
}
do this.AddRange(getter(tFrom, tTo) ) //primary constructor required

This code gives two errors:

>'tFrom = …'It means'tTo not defined' and tTo is obviously in
Range; As a workaround, I can repeat the defaultArg call as shown in the following (comment) line. Is there a better way?
>In the last line of calling "AddRange", it complains that the call can only be performed in the main constructor, which is fair. But how to call the necessary AddRange to initialize the list? I tried different options, but couldn't find a way. The comment is shown in the commented inheritance line, but in the end I call defaultArg repeatedly and redundantly; there must be a clearer and more elegant way

This is the syntax you are looking for:

module File1< br />
open System
open System.Collections.Generic

type TimeRangeList<'e> =
inherit List<'e>
val tFrom : DateTime
val tTo: DateTime
new (getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) as this =
let to_ = defaultArg maybe_tTo DateTime.Now
let from_ = defaultArg maybe_tFrom (to_.AddDays(-1.0))
{
inherit List<'e>()

tTo = to_
tFrom = from_
}
then
this.AddRange(getter(this.tFrom, this.tTo))

Document link:

>In other constructors, use the then keyword instead of do
>In the additional constructor put as this after The self-quoting name of the instance defined in the new() expression

For To explain, the {field = value; field2 = value2) syntax does not have to be the only expression found in the new() block that defines the auxiliary constructor. It only needs to be the last expression, the expression returned. (Here, even Technically, the then block is the "last" block in the constructor, and its return value (which needs to be unit) will also be ignored, and the actual return value of the constructor is the last expression not found in the then block. ). , You can safely use let expressions to define the values ​​to be put into the fields of the class, and let the expressions refer to each other like in ordinary code. Therefore, if you need to put complex or expensive calculations into multiple fields , You can do this:

new () =
let result = expensiveCalculationIWantToDoOnlyOnce()
{field1 = result; field2 = result + 1; field3 = result + 2 }

I have this F# class

module File1

open System
open System.Collections.Generic

type TimeRangeList<'e>(getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) as this =
inherit List<'e>()
//inherit List<'e>(getter(defaultArg maybe_tTo DateTime.Now, defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays (-1.0))))

let tTo = defaultArg maybe_tTo DateTime.Now
let tFrom = defaultArg maybe_tFrom (tTo.AddDays(-1.0))
do this.AddRange( getter(t From, tTo))

Now I want to add a constructor and use the syntax from here

type TimeRangeList<'e> = 
inherit List<'e>
val tFrom: DateTime
val tTo: DateTime
new (getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) = {
inherit List<'e>()
//inherit List<'e>(defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0)), getter(defaultArg maybe_tTo DateTime .Now))

tTo = defaultArg maybe_tTo DateTime.Now
tFrom = defaultArg maybe_tFrom (tTo.AddDays(-1.0)) //tTo undefined
//tFrom = defaultArg maybe_tFrom ((defaultArg maybe_tTo DateTime.Now).AddDays(-1.0))
}
do this.AddRange(getter(tFrom, tTo)) //primary constructor required

The code gives two errors:

>'tFrom = …'It means'tTo not defined' and tTo is obviously in the range of
; as a workaround, I can repeat the defaultArg call, such as The following (comment) line as shown in the picture. Is there a better way?
>In the last line of calling "AddRange", it complains that the call can only be performed in the main constructor, which is fair. But how to call the necessary AddRange to initialize the list? I tried different options, but couldn't find a way. The comment is shown in the commented inheritance line, but in the end I call defaultArg repeatedly and redundantly; there must be a clearer and more elegant way

This is the syntax you are looking for:

module File1

open System
open System.Collections.Generic

type TimeRangeList<'e> =
inherit List<'e>
val tFrom: DateTime
val tTo: DateTime
new (getter: DateTime * DateTime -> List<'e>, ?maybe_tFrom: DateTime, ?maybe_tTo: DateTime) as this =
let to_ = defaultArg maybe_tTo DateTime.Now
let from_ = defaultArg maybe_tFrom (to_.AddDays(-1.0))
{
inherit List<'e>()

tTo = to_
tFrom = from_
}
then
this.AddRange(getter(this.tFrom, this.tTo))

Document link:

>In other constructors, use the then keyword instead of do
>put as this after the new() expression in the additional constructor Define the self-quoting name of the instance in

In order to explain, the {field = value; field2 = value2} grammar does not have to be the new() that defines the auxiliary constructor The only expression found in the block. It only needs to be the last expression, that is, the returned expression. (Here, even if the then block is technically the "last" block in the constructor, its return value (need to be unit) Will also be ignored. The actual return value of the constructor is the last expression not found in the then block. ). Therefore, it is safe to use let expressions to define the value to be put into the field of the class, and let the expression Formulas can refer to each other as in ordinary code. Therefore, if you need to put complex or expensive calculations into multiple fields, you can do this:

new () =
let result = expensiveCalculationIWantToDoOnlyOnce()
{field1 = result; field2 = result + 1; field3 = result + 2 }

Leave a Comment

Your email address will not be published.