7

I have the following code:

public abstract class A ...
public class B : A ...
public class C : A ...

void my_fct(A x) {
  if (x is B) { block_1 }
  else if (x is C) { block_2 }
  else { block_3 }
}

and I wonder if it is a good translation from F#

type a = B | C
let my_fct x =
  match x with
  | B -> ( block_1 )
  | C -> ( block_2 )
  | _ -> ( block_3 )

??

Brian
  • 117,631
  • 17
  • 236
  • 300
Hugo
  • 535
  • 1
  • 3
  • 13
  • I guess it's okay. Except that you're missing ; after block_1, block_2 and block_3 – Theun Arbeider Sep 07 '11 at 12:42
  • 2
    Excuse my ignorance, but it seems to be `block_3` can never be executed in the F# snippet (algebraic data types are "closed" as far as I know), so why is it there? Also, am I the only one thinking the translation should use polymorphism? –  Sep 07 '11 at 12:44
  • You're all absolutly right about block_3. – Hugo Sep 07 '11 at 13:08
  • 3
    F# pattern-matching compiles to a jump in assembly, therefore it is O(1) in the number of union cases. To match performance in C#, you should have an int or enum encoding case number, and pattern-matching encoded as a switch statement. – t0yv0 Sep 07 '11 at 17:41

2 Answers2

13

F# discriminated unions correspond to OO class hierarchies quite closely, so this is probably the best option. The most notable difference is that you cannot add new cases to a discriminated union without modifying the type declaration. On the other hand, you can easily add new functions that work with the type (which roughly corresponds to adding new virtual methods in C#).

So, if you don't expect to add new inherited classes (cases), then this is the best option. Otherwise, you may use F# object types (or other options, depending on the scenario).

One more point regarding your code - since you cannot add new cases, F# compiler knows that the only cases you need are for B and C. As a result, the block_3 can never be executed, which means that you can write just:

let my_fct x = 
  match x with 
  | B -> ( block_1 ) 
  | C -> ( block_2 ) 
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
8

yes this is more or less the same as F# does anyhow. In this case (no values added) - F# seems to translate this into a classs for "a" and some Tags (enumeration). The class for "a" just has some static properties for B and C, and some methods to check if an object of type "a" is "B" or "C" (see below)

Object-Browser of the types

But you don't need the "_ -> (block_3)" case, because this can never be matched (F# knows all the possible cases and will warn you).

I think it's better if you throw an exception in C# for this "else" case.

Random Dev
  • 51,810
  • 9
  • 92
  • 119