Brian's profileInside F#BlogGuestbookNetwork Tools Help

Blog


    November 28

    What does this C# code look like in F#? (part one: expressions and statements)

    If you have C# code and just try to transliterate it directly to F#, the F# code you wind up with is unlikely to be idiomatic or "good".  Nevertheless, when you are new to a language (F#), it is sometimes useful to know how to transliterate from a well-known language (C#) for those cases where you just don't know the idioms yet, but don't want that to prevent you from making progress.  So today's blog entry takes the general form of "here's some C# code, how do I write the same thing in F#".  It is intended to be used as a reference or as casual reading to discover some little-used or lesser-known F# syntax/operators/functions.  Don't use this blog post as a way to learn the language, instead use the many useful F# tutorials and samples on the web (start here), and just use this blog post to "fill in the gaps" if needed.

    Today's blog entry covers only code that goes inside a method body, so you won't find anything about declaring classes or using namespaces here.  Instead I will be covering the following bits of C#:

    • casts
    • operators
    • expressions
    • statements

    and show a way to transliterate those C# forms into the corresponding F#.  Along the way I will inject some editorial comments about what is good, bad, idiomatic, etc, but I will not go into much detail.  If I leave anything common out, or something is very unclear, feel free to post a question as a comment on this blog entry.

    Without further ado!

    Casts

    The cast "operator" in C# (saying "(Typename)expr") can mean all kinds of different things in C#, depending on the source type and destination type.  I will just call out the four most common conversions done via casts:

        // C#
        char c = 'a';
        int x = (int)c;         // numerical conversion
        object o = (object)c;   // boxing conversion
        Dog d = new Dog();
        Animal a = (Animal)d;   // upcast
        d = (Dog)a;             // downcast (may fail at runtime)

    Here is the corresponding F# code, followed by some commentary.

        // F#
        let c = 'a'
        let x = int c        // numerical conversion
        let o = box c        // boxing conversion
        let d = new Dog()
        let a = d :> Animal  // upcast
        let d2 = a :?> Dog   // downcast (may fail at runtime)

    Numerical conversions in F# are done via library functions.  For example, the function "int" converts a char (or a float or a uint or a whatever) into an int.  There are similar functions for each destination type, so for example the function "char" converts it argument to a char.  You can read a little more about these functions in the library reference.  Note that the "enum" function converts to an enumerated type; the specific enumeration type will be inferred, which sometimes requires a type annotation, as in

        let y : MyEnumType = enum 0 // F#: y is 0-value of MyEnumType

    A boxing conversion turns a primitive value into an object.  The F# function "box" does this.  In fact, "box" will upcast anything to the object type System.Object (which in F# goes by the shorthand name "obj").

    Upcast: If you want to make a conversion that goes up a class/interface hierarchy, use the F# syntax "expr :> type".  If this compiles, then this conversion will always succeed at runtime.  (Note: in F# 1.9.6.2, this expression form has somewhat weird precedence, and so you may sometimes need to surround it with parens, e.g. "(expr :> type)" to make the code parse.)  You rarely need to use this operator.

    Downcast: If you want to make a conversion that goes down a class/interface hierarchy, use the F# syntax "expr :?> type".  The question mark inside this operator is meant to suggest that the operation may fail; just as in C#, you may get an InvalidCastException.  You should rarely use this operator; in C# you typically prefer "is" and "as", see those expressions below for the corresponding idiomatic F#.

    Operators

    Many arithmetic (e.g. +, *) and conditional (e.g. &&, ||) operators are the same in F# as in C#.  The most common places to get tripped up are (1) with logical negation: in C# it is spelled "!", whereas in F# it is spelled "not"; (2) with equality testing, in C# it is "==" whereas in F# it is just "="; and (3) with inequality, where C# has "!=" whereas F# has "<>".  (As for logical negation, note that "!" already has a meaning in F# associated with the "ref" type, which is inherited from OCaml, oh well.)  The other somewhat common place to get tripped up is that in C# the bitwise-logic operators are one character (e.g. "|" and "&"), whereas the F# operators are three characters ("|||" and "&&&"); you'll need these operators when using e.g. "Flags" enums.

    Most F# operators are overloaded, don't be fooled by the type inference tooltips when hovering over code like this in Visual Studio:

    let f x y = x + y  // hover mouse over f, says int -> int -> int

    This does not mean that "+" only works on ints; you can use "+" to add two floats, or two chars, or even two strings.  (The mechanism by which this overloading works involves esoteric black magic involving "inline" and "^a" types.  You'll be happier if you stay ignorant of those details; the language/tooltips pick "int" as a default when things are otherwise unconstrained in order to hide the underlying complexity.  (A much better "solution" to "how to overload common operators like '+'" is to use type classes, but neither the CLR nor even F# have sufficiently expressive type systems to handle type classes, oh well.))

    In C#, the same operator ('=') is used for both initialization and destructive assignment:

        int i = 3;    // initialization
        i = 4;        // destructive assignment

    In F#, these are separate operators ('=' and '<-'), and only mutable variables admit assignment:

        let i = 3    // initialization
        i <- 4       // does not compile, i is immutable
        let mutable j = 3
        j <- 4       // destructive assignment
     

    Expressions

    Most expressions involving constructing objects, methods, and properties look the same in C# and F#:

        new Dog()  // constructor
        s.StartsWith("h", StringComparison.Ordinal)  // method call
        s.Length   // property

    One notable difference is the syntax for indexing of arrays or other types.  Whereas in C# you say:

        var dict = new Dictionary<string, int>();
        dict["foo"] = 42;
        Console.WriteLine(dict["foo"]);

    in F# you need a dot ('.') before the square brackets:

        let dict = new Dictionary<string,int>()
        dict.["foo"] <- 42
        printfn "%d" dict.["foo"]

    There are tons of variations of syntax for doing lambdas/delegates in C#, I'll show only one:

        Func<int, int, int> f = (x, y) => x + y;  // C# lambda

    and the roughly corresponding F#:

        let f = (fun x y -> x + y)  // F# lambda

    There are lots of interesting differences between the language when it comes to representing lambdas/functions/delegates, and I will not go into any detail about these differences in today's blog entry.

    Both C# and F# have "typeof" that returns a System.Type, but C# uses round brackets whereas F# uses angle brackets:

        typeof(int// C# typeof
        typeof<int// F# typeof

    Another distinction involves generic types; C# allows you to omit types to get the generic definition:

        Console.WriteLine(typeof(List<int>).IsGenericTypeDefinition); // false
        Console.WriteLine(typeof(List<>).IsGenericTypeDefinition);    // true

    whereas F# has a separate operator called "typedefof" for getting uninstantiated generic types:

        printfn "%A" (typeof<List<int>>.IsGenericTypeDefinition)  // false
        printfn "%A" (typedefof<List<_>>.IsGenericTypeDefinition) // true

    C# has "is" and "as" operators for type tests.  F# uses a particular pattern in a match for this.  So this C# code:

        if (animal is Dog)
        {
            Dog dog = animal as Dog;
            // ...
        }
        else if (animal is Cat)
        {
            Cat cat = animal as Cat;
            // ...
        }

    becomes this F# code:

        match animal with
        | :? Dog as dog -> // ...
        | :? Cat as cat -> // ...

    where ":? type" is a type test, and "as ident" names the resulting value of that type if the type test succeeds.  (One other aside: in F# "else if" can be abbreviated as "elif".)

    C# has the ternary operator "?:" for conditional expressions:

        condition ? trueVal : falseVal

    F# has the same operator, but its name is if-then-else:

        if condition then trueVal else falseVal

    (Note that "if" is used much less frequently in F# than in C#; in F#, many conditional expressions are done via pattern-matching rather than if-then-else.)

    C# has an operator called "default" that returns the zero-initialization value of a given type:

        default(int)

    It has limited utility; most commonly you may use default(T) in a generic.  F# has a similar construct as a library function:

        Unchecked.defaultof<int>

    These respective constructs are rarely used in C# and F#.

    Statements

    This section describes how to transliterate C# statements into F#.  F# doesn't have "statements", per se; everything is just an expression, and evaluating a a method body just means evaluating its expressions.  The expressions that are most statement-like in F# just return "()", the sole value of the "unit" type, which is akin to "void" in C#.

    C# has three looping constructs:

        // C# loops
        while (condition)
        {
            SomeCode();
        }
        foreach (var e in someEnumerable)
        {
            SomeCode();
        }
        for (int i = 0; i < 10; ++i)
        {
            SomeCode();
        }

    F# has just "while" and a "foreach" (spelled "for" in F#); a C# "for" loop can usually be emulated with a "range":

        // F# loops
        while condition do
            SomeCode()
        for e in someEnumerable do  // foreach
            SomeCode()
        for i in 0..9 do  // compiles like a C# for loop
            SomeCode()

    F# lacks anything like "break" or "continue"; you must use control flow and/or boolean flag variables to emulate these constructs.  "While" loops in F# are rare, since they imply mutable variables in the condition, and F# often eschews mutables, preferring recursion for simple loops.  For(each) loops are also somewhat rarer in F#, since sometimes the form

        someEnumerable |> Seq.iter (fun e -> SomeCode())

    is preferred (especially when the argument to Seq.iter is short). 

    C# has a switch statement.  It looks something like this:

        switch (x)
        {
            case 1:
                SomeCode();
                break;
            default:
                SomeCode();
                break;
        }

    In F#, this is just one of many things that pattern matching expresses more succinctly:

        match x with
        | 1 -> SomeCode()
        | _ -> SomeCode()  // _ is a 'catch all' default

    C# has a "return" keyword that exits the current function.  There is no comparable construct in F#.  Note that the "return" keyword in F# is part of computation expression syntax (a.k.a. "workflows", a.k.a. "monads") and has nothing to do with C#'s "return".  As with C#'s "break", in F# you will need to use control-flow constructs to simulate "return" for an early exit.  (Though I do occasionally wish for "break" in F#, I have never wished for "return" - I don't recall ever needing/wanting it.)

    In C#, you raise an exception with the "throw" keyword.  In F#, you use the function "raise". 

        throw new Exception("boom");    // C#
        raise <| new Exception("boom")  // F#

    This is one of the few places in F# where I think it is very idiomatic to use the backward-pipeline operator "<|".  Without it, the precedence rules of F# force you to parenthesize the expression:

        raise( new Exception("boom") )  // F#

    which I think most people feel looks awkward.

    C# has a try-catch-finally construct for exception handling.  As a result you can write code like this:

        try
        {
            SomeCode();
        }
        catch (NullReferenceException nre)
        {
            // swallow it
        }
        catch (Exception e)
        {
            throw;
        }
        finally
        {
            SomeOtherCode();
        }

    The equivalent F# code would be:

        try
            try
                SomeCode()
            with 
                | :? NullReferenceException as nre -> () // swallow it
                | e -> rethrow()
        finally
            SomeOtherCode()

    There are a few things to point out here.  First, in F#, try-with and try-finally are separate constructs - there is no try-with-finally.  In practice, you usually only do one or the other (and you should probably be using try-finally about ten times as often as try-catch, in either language - catching exceptions is rarely the right thing to do).  F# "catch" blocks just use pattern matching type tests on the exception, much like we saw earlier with the transliteration of C# "is"/"as".  In F#, to re-throw the exception, use "rethrow()". 

    C# has a "checked" statement for checking for arithmetic overflow; F# has checked operators in the library, so just open this namespace and use the operators there if you need overflow checking.

    C# has a "lock" statement for locking an object for a critical section:

        lock (o)             // C# lock
        {
            SomeCode();
        }

    In F#, "lock" is a function that takes the lock object and a lambda of the critical section:

        lock o (fun () ->    // F# lock
            SomeCode()
        )

    C# has "using" for IDisposables:

        using (var disp = someDisposable)
        {
            SomeCode();
        }

    F#'s corresponding syntax:

        use disp = someDisposable 
        SomeCode()

    F#'s "use" is like "let", it is scoped to the end of the surrounding block.

    Inside a C# method that returns an IEnumerable, the following "yield" statement forms are allowed:

        yield return 42// C# yield a value
        yield break;      // C# end the enumeration

    In F#, you don't have to declare a method-returning-IEnumerable to use "yield", instead you can make a sequence expression anywhere using "seq{...}":

        let myIntSeq : IEnumerable<int> = seq { yield 42; }

    I added a type annotation just to remind you that "seq" in F# just means "IEnumerable".  So the sequence expression on the right-hand-side of the line of code above evaluates to an IEnumerable<int> that yields a single value (42).  As with a C# iterator block, you can put arbitrary code using yields in an F# sequence expression.  Just as with loops and C# "break", there is no "yield break" in F#.

    The end

    I think that just about covers all the interesting C# expressions and statements, showing the corresponding F# counterparts.  I hope this is a useful reference for filling in gaps in your F# knowledge while learning F#.

    Comments (5)

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.
    Brian McNamara has turned off comments on this page.
    chunmin xiawrote:
    I really do not understand why F# introduces so many different syntax from C#?
    If similar sntax to c# is used for F#, what happens?
    so many abnormal operators adopted by F#!
    May 30
    Santiagowrote:
    Great Job, I'm learning F# from C# and your post is useful. Thanks
    Dec. 25
    No namewrote:
    > there is no try-with-finally
    I think F# designers repeat some of Python's design mistakes. This one was corrected in Python 2.6, so somebody really needed it.
    > In practice, you usually only do one or the other
    Are you sure? Are you going to suggest removing it from C# too? Or are you just justifying this stupid design decision?
    Dec. 18
    Pavel Minaevwrote:
    > F# has just "while" and a "foreach" (spelled "for" in F#); a C# "for" loop can usually be emulated with a "range"

    That's incorrect, F# actually has a traditional Pascal-style for-loop:

    for i = 1 to 10 do SomeCode(i)
    for i = 10 downto 1 do SomeCode(i)
    Dec. 9
    Sam Stokeswrote:
    Great job!
    Dec. 1

    Trackbacks

    Weblogs that reference this entry
    • None