I try to understand the concept of boxing and testing for base types, especially with tuples.
I have two objects from an external C# library that have different concrete types but share a common base type:
let o1 = ConcreteType1() // has base type BaseType
let o2 = ConcreteType2() // also has base type BaseType
If both o1 and o2 are derived from BaseType, I have to perform some special comparison logic, so I'd like to test whether the elements of a tuple (o1, o2) both have base type BaseType.
Based on the answers to this question, I gather that I have to box each element of the type separately and perform the type tests on the individual elements, so that base types are considered:
match box o1, box o2 with
| (:? BaseType), (:? BaseType) -> // special logic with o1, o2
| _ -> // nope, some other behavior
My understanding is that simply boxing the tuple itself will not upcast the individual elements to obj, and the test for their base types will therefore not work:
match box (o1, o2) with
| :? (BaseType * BaseType) -> // never hit, because elements are not upcast to obj
| _ -> // ...
Is this the correct explanation for the observed behavior, or are there other mechanisms involved?
It's true that boxing a tuple doesn't box the tuple's items. However, even if you manually boxed the items as well, it still wouldn't match. So the following code prints
"Unknown":This is because
ConcreteType1 * ConcreteType2is not a subtype of eitherBaseType * BaseTypeorobj * obj. Note that the following code won't even compile:That means the following code will print
"ConcreteType":This is just the way that polymorphic types interact with OO subtyping. As another example,
List<ConcreteType1>isn't a subtype ofList<BaseType>, so no amount of boxing and casting will get them to match either.The confusing thing is that F# does have a special case where it will automatically cast a
ConcreteType1 * ConcreteType2argument to match aBaseType * BaseTypeparameter:I think this is because tupled arguments are common in other languages, so F# is trying to maintain compatibility, but I'm not certain.