classinheritancef#type-constraintssubtyping

F# type constrains subtyping


I got a question, mostly because I found a case where classes and subtyping was needed.

let say we got some function

let IsA<'item, 'input> (subject: 'input) = 
    match subject with
    | :? 'item as item -> Some item
    | _ -> None

is there a way to constraint the generic types to allow this.

The alternative is to do a IsA function for all subtype constrains.

This is a dummy case, but it clearly describes what I need to do.


Solution

  • I'm not exactly sure what your motivation here is. You can certainly box the subject before pattern matching on the value:

    let IsA<'item, 'input> (subject: 'input) = 
        match box subject with
        | :? 'item as item -> Some item
        | _ -> None
    

    This lets you call IsA on various things, including the ones that make sense (but also, because of the boxing, some that cannot possibly make sense). You need to constrain the 'item type parameter, either by explicitly saying IsA<Cat, _> or by having an annotation elsewhere:

    type Animal() = class end
    type Dog() = inherit Animal()
    type Cat() = inherit Animal()
    let dogAnimal = Dog() :> Animal
    
    let asCat : Cat option = IsA dogAnimal
    let asDog : Dog option = IsA dogAnimal
    let asCat2 : Cat option = IsA (System.Random())
    

    In principlie, it would be nice if the last case with Random was not allowed. Unfortunately, you cannot specify a constraint for this though. The following does not work:

    let IsA<'item, 'input when 'item :> 'input> (subject: 'input) = 
        match subject with
        | :? 'item as item -> Some item
        | _ -> None
    

    The issue is discussed, for example, here: How to constrain one type parameter by another