Knows Not Much
Knows Not Much

Reputation: 31546

A very basic Type check fails in F# ... why?

I wrote this code

type Test =
    | Age of int
    | Name of string;;

let x = Age(10);;


if (x.GetType() = typeof<Test>) then printfn "true" else printfn "false";;

The code prints false. But that puzzles me because isn't Age of type Test?

Also, is there a better way to compare types in F# the .GetType() = typeof<> is very long. I tried :? but I think that's for typecasting rather than comparing types.

Upvotes: 4

Views: 871

Answers (3)

J D
J D

Reputation: 48687

But that puzzles me because isn't Test of type Color?

There is no type Color and Test is a type itself so it does not have a type. So your question is nonsensical.

Perhaps you meant to ask why the answer is what it is? If so, it is a consequence of the way F# currently chooses to represent such values internally.

Upvotes: -2

John Palmer
John Palmer

Reputation: 25516

Quoting from the spec

A compiled union type U has:

· One CLI static getter property U.C for each null union case C. This property gets a singleton object that represents each such case.

· One CLI nested type U.C for each non-null union case C. This type has instance properties Item1, Item2.... for each field of the union case, or a single instance property Item if there is only one field. However, a compiled union type that has only one case does not have a nested type. Instead, the union type itself plays the role of the case type.

We see that Age is implemented as a nested type of the parent DU. As a result you could use Type.GetNestedTypes to get all the subtypes of the DU and then test each one to see if the type matches.

Upvotes: 2

Ramon Snir
Ramon Snir

Reputation: 7560

The plain answer is, do so:

if (x :> obj) :? Test then printfn "true" else printfn "false"

This issue comes because of the implementation of DUs (using internal classes and tags) and the limitation of F#'s type system (which does not acknowledge the implementation).

As you saw, the type of x is FSI_0001+Test+Age, and F# does not recognize that as a sub-type of Test.

Upvotes: 4

Related Questions