F# discriminated unions versus C# class hierarchies - c#

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 )
??

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 )

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)
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.

Related

Pattern matching F# type in a C# code

Suppose there is a F# definitions:
type Either<'a,'b> = | Left of 'a | Right of 'b
let f (i : int) : Either<int, string> =
if i > 0
then Left i
else Right "nothing"
Function f is used in C# code:
var a = Library.f(5);
How the result value a could be pattern matched for data constructors? Something like:
/*
(if a is Left x)
do something with x
(if a is Right y)
do something with y
*/
Using F# discriminated unions from C# is a bit inelegant, because of how they are compiled.
I think the best approach is to define some members (on the F# side) that will simplify using the types from C#. There are multiple options, but the one I prefer is to define TryLeft and TryRight methods that behave similarly to Int32.TryParse (and so they should be familiar to C# developers using your F# API):
open System.Runtime.InteropServices
type Either<'a,'b> =
| Left of 'a
| Right of 'b
member x.TryLeft([<Out>] a:byref<'a>) =
match x with Left v -> a <- v; true | _ -> false
member x.TryRight([<Out>] b:byref<'b>) =
match x with Right v -> b <- v; true | _ -> false
Then you can use the type from C# as follows:
int a;
string s;
if (v.TryLeft(out a)) Console.WriteLine("Number: {0}", a);
else if (v.TryRight(out s)) Console.WriteLine("String: {0}", s);
You lose some of the F# safety by doing this, but that's expected in a language without pattern matching. But the good thing is that anybody familiar with .NET should be able to use the API implemented in F#.
Another alternative would be to define member Match that takes Func<'a> and Func<'b> delegates and invokes the right delegate with the value carried by left/right case. This is a bit nicer from the functional perspective, but it might be less obvious to C# callers.
I'd define a Match member taking the delegates to execute in each scenario. In F# you'd do it like this (but you could do something equivalent in a C# extension method, if desired):
type Either<'a,'b> = | Left of 'a | Right of 'b
with
member this.Match<'t>(ifLeft:System.Func<'a,'t>, ifRight:System.Func<'b,'t>) =
match this with
| Left a -> ifLeft.Invoke a
| Right b -> ifRight.Invoke b
Now you should be able to do something like this in C#:
var result = a.Match(ifLeft: x => x + 1, ifRight: y => 2 * y);
From the 3.0 spec:
8.5.4 Compiled Form of Union Types for Use from Other CLI Languages
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.
One CLI static method U.NewC for each non-null union case C. This method constructs an object for that case.
One CLI instance property U.IsC for each case C. This property returns true or false for the case.
One CLI instance property U.Tag for each case C. This property fetches or computes an integer tag corresponding to the case.
If U has more than one case, it has one CLI nested type U.Tags. The U.Tags typecontains one integer literal for each case, in increasing
order starting from zero.
A compiled union type has the methods that are required to implement its auto-generated interfaces, in addition to any
user-defined properties or methods.
These methods and properties may not be used directly from F#.
However, these types have user-facing List.Empty, List.Cons,
Option.None, and Option.Some properties and/or methods.
A compiled union type may not be used as a base type in another CLI
language, because it has at least one assembly-private constructor and
no public constructors.
If you can't change the F# api, using points 2 and 4 above you could do it something like this:
C#
class Program
{
static void Main(string[] args)
{
PrintToConsole("5");
PrintToConsole("test");
}
static void PrintToConsole(string value)
{
var result = test.getResult(value);
if (result.IsIntValue) Console.WriteLine("Is Int: " + ((test.DUForCSharp.IntValue)result).Item);
else Console.WriteLine("Is Not Int: " + ((test.DUForCSharp.StringValue)result).Item);
}
}
F#
namespace Library1
module test =
open System
type DUForCSharp =
| IntValue of int
| StringValue of string
let getResult x =
match Int32.TryParse x with
| true, value -> IntValue(value)
| _ -> StringValue(x)
This solution is convenient in that it also handles tuple DU cases by creating a new property for each item in the tuple.

Automatically refactor code to avoid parameterless constructor

I have a class that has a parameterless constructor that I want to remove (or make private)
class C
{
string A { get; set; }
int B { get; set; }
public C() { } //Problem
public C(A a, B b)
{
A = a;
B = b;
}
}
Problem is, the code base is littered with hundreds of expressions such as new C {A = a, B = b}, or new C() { B = b, A = a }, in every conceivable variation, ordering of fields, etc. (I didn't know that the brackets were optional until today).
Is there any automated way of fixing up my code to use the 2 argument constructor? The changes are trivial, but I think I'll go insane if I have to do it manually.
My examples have 5 or 6 arguments, and not all are required, etc.
(The motivation is to make the class immutable. Hiding the parameterless constructor and the public setters is the first step)
I've had a small amount of success with regular expressions (Notepad++'s regex support seems to stop after 4 captures), but writing a complex regex to fix 6 items at a time doesn't actually save me a great deal.
You can use the ability to explicitly specify named arguments in a function call (including a constructor) to fix this relatively easily.
Specifically, you can replace
C() { B = b, A = a }
with
C(B: b, A: a)
and the constructor will behave correctly. This will work regardless of the order of the arguments, so long as they're all either specified or optional.
Here's an entirely different approach you can try:
Do exactly what you want to do to C. Then create a CBuilder class which has all the same properties as a C, but only has a single method:
public C Convert()
{
return new C(this.A, this.B);
}
Then, you just need to do a find/replace on new C() {...}; and change it into (new CBuilder() {...}).Convert();, which would be a single regex replacement.
This doesn't immediately solve the problem, but it does let you refactor freely, and you can make it policy that every time you work on something that uses CBuilder, you replace that instance of it with a C instead. Gradually, you'll refactor all the code, but it won't prevent you from moving forward.
Suggestion: Maybe you could make use of named parameters.
new C {A = 5, B = "tt"} is in the end equivalent to new C(A: 5, B: "tt")
So you could replace all occurences of "A =" into "A:" and "B =" into "B :"
This could be easier with temporary rename of A into NewNameForANotCollidingWithAnything so that you can do massive blind automated and safe replace.
Then replace "new C{...}" into new "C (...)" // this is the most difficult part (I did not try it)
Hope it takes you closer to what you need....
Remove your parameterless constructor completely. The compiler will fail on all it's uses and you can switch to use the 2-parameter version.

Flagged Enum Consolidation (Inverse of Combination) Using LINQ

I am trying to generate an inverse of a flagged enumeration. Below is the enum:
[Flags]
public enum MyType
{
Unknown = 0,
A = 1 << 0,
B = 1 << 2,
C = 1 << 3,
D = 1 << 4,
E = 1 << 5,
F = 1 << 6
}
I have defined a static MyType mtGroup1 with a value of (A | B). I would like to generate the inverse of this, excluding Unknown.
My solution:
MyType t = MyType.Unknown;
foreach (var vType in Enum.GetValues(typeof(MyType)).OfType<MyType>())
{
if ((mtGroup1 & vType) != vType)
t = t | vType; //Consolidates into a single enum, excluding unknown
}
The resulting value of t is C | D | E | F, which is the desired outcome.
This method works, but I was hoping there was a more simple way to consolidate as shown above using LINQ (other, non-LINQ ways are also acceptable if simpler).
Thanks!
My Unconstrained Melody project makes this really simple:
MyType inverse = mtGroup1.UsedBitsInverse();
The project contains a number of useful methods (many written as extension methods) which use "unspeakable" generic constraints (ones which are understood by the C# compiler but can't be expressed in C#) to constrain generic type parameters to be enum types or delegates. In this way, the above code manages to work without any boxing - and it actually works out all the "interesting" bits of an enum type once, the first time that type is used in conjunction with Unconstrained Melody, so this operation is blindingly efficient.
If you don't want to use Unconstrained Melody, you could write your own method to find the "used bits" of an enum once, then just use:
MyType t = UsedBitsOfMyType & ~mtGroup1;

Can I add an implicit conversion for two classes which I don't directly control?

I'd like to be able to implicitly convert between two classes which are otherwise incompatible.
One of the classes is Microsoft.Xna.Framework.Vector3, and the other is just a Vector class used in an F# project. I'm writing a 3d game in C# with XNA, and -- although it's drawn in 3D, the gameplay takes place in only two dimensions (it's a birds-eye-view). The F# class takes care of the physics, using a 2D vector:
type Vector<'t when 't :> SuperUnit<'t>> =
| Cartesian of 't * 't
| Polar of 't * float
member this.magnitude =
match this with
| Cartesian(x, y) -> x.newValue(sqrt (x.units ** 2.0 + y.units ** 2.0))
| Polar(m, _) -> m.newValue(m.units)
member this.direction =
match this with
| Cartesian(x, y) -> tan(y.units / x.units)
| Polar(_, d) -> d
member this.x =
match this with
| Cartesian(x, _) -> x
| Polar(m, d) -> m.newValue(m.units * cos(d))
member this.y =
match this with
| Cartesian(_, y) -> y
| Polar(m, d) -> m.newValue(m.units * sin(d))
This vector class makes use of the unit system used by the physics project, which takes native F# units of measure and groups them together (units of Distance, Time, Mass, etc).
But XNA uses its own Vector3 class. I want to add an implicit conversion from the F# Vector to the XNA Vector3 which takes care of which two dimensions the gameplay takes place in, which axis is "up", etc. It'd be simple, just Vector v -> new Vector3(v.x, v.y, 0) or something.
I can't figure out how to do it though. I can't add an implicit conversion in F# because the type system (rightly) doesn't allow it. I can't add it to the Vector3 class because that is part of the XNA library. As far as I can tell I can't use an extension method:
class CsToFs
{
public static implicit operator Vector3(this Vector<Distance> v)
{
//...
}
}
Is an error on the this keyword, and
class CsToFs
{
public static implicit operator Vector3(Vector<Distance> v)
{
return new Vector3((float)v.x.units, (float)v.y.units, 0);
}
public static void test()
{
var v = Vector<Distance>.NewCartesian(Distance.Meters(0), Distance.Meters(0));
Vector3 a;
a = v;
}
}
is an error on a = v; (cannot implicitly convert...).
Is there a way to do this without being able to put the cast in either of the classes? As a last resort I could open Microsoft.Xna.Framework and do the conversion in F#, but that seems wrong to me -- the physics library shouldn't know or care what framework I'm using to write the game.
No, you can't. The implicit operator has to be defined as a member of one of the classes. However, you can define an extension method (your example didn't work as extension methods have to be in a public static class).
public static class ConverterExtensions
{
public static Vector ToVector (this Vector3 input)
{
//convert
}
}
In C# you cannot. You could provide descendant types that have the extra conversions (provided the types aren't sealed); Or you could provide a generic wrapper class that somehow adds the conversion.
The convenience of all this depends on the way in which these wrappers/adaptations can be used with the original APIs.
On another note I see you are useing F# as well. IIRC F# is supposed to have some level of meta-programming ability (like many functional languages for .NET, such as Boo and Nemerle). It would not surprise me if that could be used here. Unfortunately my F is not sharp enough to help there

FSharpChoice in C#

I am trying to use FSharpChoice type in a C# project. I have created a choice like so
var a = FSharpChoice<T1,T2,T3>.NewChoice1Of3(instofT1);
now how do I get instofT1 out of the choice type.
I see I can do a IsChoice1Of3 but how do i get to the value in the choice object?
I probably wouldn't use the type directly from C# - you can do that, but the resulting code won't be very nice. I'd probably declare my own Choice type that would look like this:
type Choice<'T1, 'T2> private (opt1, opt2) =
member x.TryGetChoice1Of2(arg:byref<'T1>) = //'
match opt1 with
| Some v -> arg <- v; true
| _ -> false
// Similar code for 'TryGetChoice2Of2'
type Choice = // static methods for creating (Choice1Of2, ...)
This uses byref parameters which appear as out parameters in C#, so you could write:
int num;
string str;
if (choice.TryGetChoice1Of2(out num)) // ...
else if (choice.TryGetChoice2Of2(out str)) // ...
else // assert(false)
This is definitely more pleasant way of working with the type from C# (and it uses pattern familiar from, for example, working with Int32.TryParse).
Cast the value to FSharpChoice<T1,T2,T3>.Choice1Of3 and use the Item property.
See Compiled Form of Union Types for Use from Other CLI Languages in the F# spec for more information about how discriminated unions are represented.
I recently started a project to make a "compatibility layer" so that FSharp.Core can be more easily consumed from C#. In particular, it makes generic discriminated unions usable from C#, for example:
var choice = Choice.New1Of3<int,string,string>(100);
int r = choice.Match(i => i + 21, s => s.Length + 1, s => s.Length + 5);
This does pattern matching on the discriminated union, similarly to how you would do it in F#, except there are no names.

Categories

Resources