I have a class called 'Pane' (think glass pane) that implements IPane:
type IPane =
abstract PaneNumber : int with get, set
abstract Thickness : float<m> with get, set
abstract ComponentNumber : int with get, set
abstract Spectra : IGlassDataValues with get, set
...
type Pane(paneNumber, componentNumber, spectra, ...) =
let mutable p = paneNumber
let mutable n = componentNumber
let mutable s = spectra
...
interface IPane with
member this.PaneNumber
with get() = p
and set(value) = p <- value
member this.ComponentNumber
with get() = n
and set(value) = n <- value
member this.Spectra
with get() = s
and set(value) = s <- value
...
I create a list of panes (Pane list):
let p = [ p1; p2 ]
however I need to cast this to an IPane list as this is a parameter type in another function. The following code produces an error:
let p = [ p1; p2 ] :> IPane list
'Type constraint mismatch. The type
Pane list
is not compatible with type
IPane list
The type 'IPane' does not match the type 'Pane'
This is confusing as Pane implements IPane. Simply passing the Pane list object as a parameter into the required function also produces an error.
How do I cast Pane list to IPane list?
F# doesn't allow inheritence in quite the way you want.
A better way would be to use:
[p1 ;p2] |> List.map (fun x -> x:> IPane)
Alternatively, you can change your function to use something like this
let f (t:#IPane list) = ()
and here you can do f [p1;p2]
as the #
tells the compiler that any type that inherits from IPane
is fine.
Another way would have been like this:
let p = [p1; p2] : IPane list
// or equivalently
let p : IPane list = [p1; p2]
In your original code, what happened is that first it inferred the type of [p1; p2]
without any constraints, which it found to be Pane list
, and then it tried to upcast it to IPane list
, which it couldn't do because F# has strict variance rules: even if Pane
is a subtype of IPane
, Pane list
is not a subtype of IPane list
.
In my code above, on the other hand, instead of trying to infer the type of [p1; p2]
, it verifies that it can match the type IPane list
that it was given; and in doing so, it implicitly upcast the individual list elements p1
and p2
to IPane
.
The solution was easier than I thought.
I was defining p1 and p2 as:
let p1 = new Pane(1, 2, blah, blah)
let p2 = new Pane(2, 2, blah, blah)
However if I cast them as IPanes at this point, everything works:
let p1 = new Pane(1, 2, blah, blah) :> IPane
let p2 = new Pane(2, 2, blah, blah) :> IPane
John Palmer's solution above is probably more rigorous as the original pane objects are maintained as the concrete types.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With