1

The use of type typedef<typename> as a literal target within a match expression or when supported by an active expression as shown here shows syntax error on the typeof<> portion of the expression. Am I doing something wrong?

(Note that the match is against an instance of Type and not an actual value of that type.)

let (|IsType|_|) (et:Type) t = if et.Equals(t) then Some() else None

let someFunc someType =
    match someType with
    | IsType (typeof<string>) _ -> "Yes"
    | _                         -> "No"

Interestingly, within an if..then expression it does work.

let someFunc someType =
    if typeof<string> = someType then "Yes"
    else "No"
    )

This circumstance would appear to be an oversight in the language.

George
  • 2,451
  • 27
  • 37

2 Answers2

2

This is a restriction of the F# language syntax - the things that can appear in a pattern (even when it is an active pattern) have to be syntactically patterns. So you can write IsSomething 123 because IsSomething and 123 are valid patterns, but you cannot write IsType typeof<Foo> because typeof<Foo> cannot be parsed as a pattern.

One workaround is to pass the argument as a quotation - I would probably not do this because it looks uglier and it is slower than doing a normal if, but it works:

open Microsoft.FSharp.Quotations

let (|IsType|_|) (et:Expr<'T>) (t:System.Type) = 
  if t.Equals(typeof<'T>) then Some() else None

let someFunc someType =
    match someType with
    | IsType <@ Unchecked.defaultof<string> @> -> "Yes"
    | _ -> "No"

It uses Unchecked.defaultof just to get a quotation of type string - but you could provide any other quotation of the type, so IsType <@ "nada" @> would work too.

EDIT: In the F# language specification, the allowed syntax is defined in section 7:

pat-param :=
    | const 
    | long-ident 
    | [ pat-param ; ... ; pat-param ]
    | ( pat-param, ..., pat-param )
    | long-ident pat-param 
    | pat-param : type
    | <@ expr @>
    | <@@ expr @@>
    | null 
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Thanks Tomas. Yet, isn't, `typeof` a `constant` and "should" be available in such context like all literals presumably are? – George Dec 09 '15 at 17:08
  • I added the relevant bits of the F# specification, but I completely agree that this would make sense to add. You can suggest it at: http://fslang.uservoice.com – Tomas Petricek Dec 09 '15 at 17:32
  • I will. Indeed, typeof<*> and typedefof<*> are `const`. Perhaps an upper case version could be coined: `Typedef` and `TypeDefOf`, respectively. – George Dec 11 '15 at 01:41
  • checked the comments. Some already suggested the idea and it was rejected: (http://fslang.uservoice.com/forums/245727-f-language/suggestions/5664335-allow-pattern-matching-on-types#comments). – George Dec 11 '15 at 01:59
0

The recommendation is to use the when class to perform a dynamic test as demonstrated here:

match typeValue with
    | t when t = typeof<string> -> ...
    | t when t = typeof<int> -> ...
    ...
George
  • 2,451
  • 27
  • 37