Search code examples
genericsf#type-constraints

In F#, what is difference between two generic type constraint representations


I am using Rx for a scheduling project. One of the methods looks like:

let strike (scheduler: 'a when 'a :> IScheduler option) strikeTime source =
    match strikeTime with
    | StrikeOnceAt due -> strikeOnce scheduler (Choice1Of2 due) source
    | StrikeOnceAfter delay -> strikeOnce scheduler (Choice2Of2 delay) source
    | StrikeEvery (period, last) -> strikeEvery scheduler period last source

When testing, I am using a HistoricalScheduler, which, of course, derives from IScheduler.

let ``Repeater strikes at given rate per minute`` rpm =
    let sched = new HistoricalScheduler(DateTimeOffset.Now)
    let rate = rpm |> int64 |> Min |> toRate

    let repeat = Repeater.StrikeEvery (rate, None)
    use actual = Repeater.strike (Some sched) repeat source

Instead of casting sched :> IScheduler in the calling code, I'm hoping to use type constraints like shown above.

I am unsure whether to represent the constraint as...

(scheduler: 'a option when 'a :> IScheduler) -or-
(scheduler: 'a when 'a :> IScheduler option)

Is this just preference? Is there a reason to choose one way over the other?


Solution

  • When deciding between

    (scheduler: 'a option when 'a :> IScheduler) -or-

    (scheduler: 'a when 'a :> IScheduler option),

    the compiler will tell you that the first variant resolves as

    (scheduler: #IScheduler option)

    while the second should generate a warning that it has been constrained to

    (scheduler: IScheduler option).

    Therefore your first variant does actually what you want it to do. The # notation is called flexible type.