Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to destructure a constructor argument?

In F# I can use pattern matching in a variety of places within the syntax.

For example:

// Given this type...
type SingleCaseUnion = | SingleCaseUnion of int

/// ...I can do this:
let destructureInFunc (SingleCaseUnion n) =
    printfn "%d" n

// ...and this:
type DestructureInMethod() =
    member t.M(SingleCaseUnion n) =
        printfn "%d" n

But I can't work out how to do this:

type DestructureInCtor(SingleCaseUnion n) =
    do printfn "%d" n

//  type DestructureInCtor(SingleCaseUnion n) =
//  ---------------------------------------^
//
// stdin(3,40): error FS0010: Unexpected identifier in type definition. Expected ')' or other token.

Do I have the syntax wrong, or does F# not support pattern matching in constructor parameters?

like image 521
Tim Robinson Avatar asked Jan 27 '15 13:01

Tim Robinson


1 Answers

No, the language spec explicitly says no:

primary-constr-args : attributesopt accessopt (simple-pat, ... , simplepat)
simple-pat :
 | ident
 | simple-pat : type

As has been pointed out, secondary constructors are allowed pattern-matched parameters, but the difference with the primary constructor is each of the primary's parameters is both a function parameter and a private field declaration.

If F# were to allow pattern matching here, there would be some patterns that would break this one-parameter-one-field relationship.

type DestructureInCtor(SingleCaseUnion _) = 
    // doesn't declare a private field

or:

type DestructureInCtor((a:int, b:int)) = 
    // declares two private fields? 

It's not inconceivable that this could work but I'm guessing the complexity of allowing pattern matching to be extended to providing field declarations outweighs the benefits.

like image 92
Tim Rogers Avatar answered Sep 29 '22 15:09

Tim Rogers