Is C# Killing Off Functional And Dynamic Languages?


C# has shown the way for bringing features like generics, type inference and lambda syntax in type safe OO languages. By so doing, has it fatally wounded the argument for dynamic and functional languages?

Microsoft have not always created the very best of software, in the case of C# they have.

Before C# the world of commercial grade OO languages was pretty much settled on Java and C++. C++ was really clever, but to make use of its powerful features was tricky for a lot of developers. Java was a lot more straight forward, *but was not a true type safe language and only had the very simplest of type inference technology (only really enough to check for type safety in those cases where it was type safe).
* In the earlier versions of Java utility classes required casting to object and back removing type safety in a lot of code.

Type inference in C# is just amazing. There is just enough to make coding easy without causing really complex side effects that your average jo struggles with.

For example, let us look at the following code in C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Tuples
{
    class Program
    {
        static void Main(string[] args)
        {
            // Example 1: Avoiding reference types
            System.Console.WriteLine("Result=" + DivAndRemainder (10 , 3));

            // Example 2: Avoiding reference types and encapsulation
            var local1 = DivAndRemainderKeepAll(26, 4);
            System.Console.WriteLine
            (
                    "Dividing " + local1.Item1 +
                    " by " + local1.Item2 +
                    " gives " + local1.Item3 +
                    " remainder " + local1.Item4
            );

            // Example 3: Function chaining
            WriteResult(DivAndRemainderKeepAll(26, 4));

            // Example 4: The horrid way
            int local2 = 26;
            int local3 = 4;
            int local4 = 0;
            var local5 = DivAndRemainderHorrid(local2, local3,ref local4);
            System.Console.WriteLine
            (
                    "Dividing " + local2 +
                    " by " + local3 +
                    " gives " + local5 +
                    " remainder " + local4
            );
        }

        static Tuple DivAndRemainder(int numerator, int denominator)
        {
            return Tuple.Create(numerator / denominator, numerator % denominator);
        }

        static Tuple DivAndRemainderKeepAll(int numerator, int denominator)
        {
            return Tuple.Create
            (
                numerator,
                denominator,
                numerator / denominator,
                numerator % denominator
            );
        }

        static int DivAndRemainderHorrid(int numerator, int denominator, ref int remainder)
        {
            remainder = numerator % denominator;
            return numerator / denominator;
        }

        static int WriteResult(Tuple result)
        {
            System.Console.WriteLine
            (
                "Dividing " + result.Item1 +
                " by " + result.Item2 +
                " gives " + result.Item3 +
                " remainder " + result.Item4
            );
        }
    }
}

In the above code the line  var local1 = DivAndRemainderKeepAll(26, 4); infers the type in local1 to be the complex, generic type Tuple. This illustrates the power of generics to make truly type safe code and type inference making using that code really easy!


            System.Console.WriteLine
            (
                    "Dividing " + local1.Item1 +
                    " by " + local1.Item2 +
                    " gives " + local1.Item3 +
                    " remainder " + local1.Item4
            );

I say easy, well above is where local1 is used; how easy is that? Visual Studio even shows you what fields and methods on one inferred types. This feature of the IDE tightly meshing with the language's strict type system further boosts the appeal of C# and the C# approach.

Note: technically, Java came out with a form of generics before C# (2004 vs 2005, a few months between releases), however C#'s implementation is much better (IMHO) and I suspect pressure from C# was at least partly responsible for Java moving in this direction.

From 'The Knife Is
Out For Ruby
Why Is This Killing Dynamic And Functional Languages?

Because C# blazed the trail:

1) Generics could be simple enough to be used by normal people [unlike templates in C++ which are quite tricky].
2) Type inference makes programming static typed languages 'feel' as easy as programming dynamic typed ones.
3) Using generics, Lambda's and closures can be implemented type safe and easily.
4) Type safety working brilliantly with an IDE for auto-suggestions, code completion and error correction.

Once C# did these other major languages started to. Java has implemented a sort of Generics. I am not going to argue it is as good as C#'s, but it exists. Even COBOL now has type inference and generics. Future versions may well have full type inference of variable type as well.

For example:
In my post on calling F# from COBOL and back I showed how the shared generics system between COBOL and F# allows the COBOL compiler to infer the types of F# functions:

invoke type ComparableQuickSort::print_list
(
    type ComparableQuickSort::quicksort
    (
        type ComparableQuickSort::toList(testList)
    )
)

The key being that all this is deceptively simple. The code above looks simple enough, here it is in C#


ComparableQuickSort.print_list
(
    ComparableQuickSort.quicksort
    (
        ComparableQuickSort.toList(testList)
    )
)


The compiler has to work out the types of the returns of each method invoke and use that type for the actually type of the generic parameter to the enclosing methods. The compiler logic to do this is quite complex (to say the least). I should know, I am technical lead for the team which maintains it for Micro Focus COBOL!

Because all these features are becoming expected in static typed, OO languages, the benefits of functional and dynamic languages are being eroded.

Indeed, this is beautifully illustrated by how well C# and F# work together.C# is doing a lot of the sorts of things functional languages used to be uniquely able to do. The ultimate question the example poses is, if C# if this good at type safe functional approaches, why bother with functional languages. I know there are good reasons, Haskell is amazing and very elegant. But, those reasons are no longer as compelling as they once were.

I know I will be flamed for saying this. I am talking about the real world of people having to 'grunt out' code day in day out. In that world, C# is fatally cutting away at the compelling reasons to use other language types!

A Final Word

I am not a huge TIOBE fan, nevertheless and for what it is worth, here is their graph showing the web activities for dynamic and static languages. The trend back to static typing is clear. One can compare this trend back to the big jump [2005-2006 C# 2.0, Java 1.4 both with Generics] and then continued growth in popularity of C# (despite it only being a small contributor to the index as a whole).

I am sure that if it were not for C# showing the way (Java, COBOL, VB following), the swing back to static typed OO languages would have been less pronounced or it might not even have happened at all!