tags:

views:

290

answers:

5

I know the "Sales pitch" answer is yes to this question, but is it technically true.

The Common Language Runtime (CLR) is designed as an intermediate language based on Imperative Programming (IP), but this has obvious implications when dealing with Declarative Programming (DP).

So how efficient is a language based on a different paradigm than the Imperative Style when implemented in the CLR?

I also get the feeling that the step to DP would incur an extra level of abstraction that might not model at all performant, would this be a fair comment?

I have done some simple tests using F# and it all looks great, but am I missing something if the programs get more complex?

+8  A: 

There is no guarantee that languages produce the same IL for equivalent code, so I can safely say that there is no guarantee that all .NET languages are equally performant.

However, if they produce the same IL output, then there is no difference.

Lasse V. Karlsen
But here lies the true question. If a language is designed with the underlying constructs of the CLR in mind, and maps the constructs isomorphically then it is a better candidate for performant apps. But this has serious implications on languages designed with declarations. I would not expect equivalent code, but if all languages are "First Class citizens" of the CLR then I would expect the performance to be equal.
WeNeedAnswers
A language can be purely functional and still be designed with the underlying machine constructs in mind. There is no requirement for isomorphism. It just requires a smarter compiler. See [dons' post on stream fusion in Haskell](http://donsbot.wordpress.com/2010/02/26/fusion-makes-functional-programming-fun/). Of course smart compiler are hard to write, so the usual approach is to provide both low-level constructs and high-level ones in the language, then optimise slow programs by changing high-to-low.
Nathan Sanders
Nice link Nathan, love it. Can you see it working with the CLR though, or is the CLR just a layer of abstraction too high to get that kind of cool smart thinking.
WeNeedAnswers
Well, the required properties are: a runtime with jumps and unboxed values, and a pure language so the compiler can reorder function composition. (Also a smart compiler.) I'm pretty sure the CLR has the first, and F# is pretty close to the second. At least, I suspect it's *easier* to prove purity in F# than in C#. If nothing else, F# language spec is closer to pure. (All you'd need to change is (1) add a computation builder named `io` and decree that all .NET interop happens there and (2) make printf and friends return io values too.)
Nathan Sanders
+2  A: 

At the end of the day, all programming languages are compiled into the native machine code of the CPU they're running on, so the same questions could be asked of any language at all (not just ones that compile to MSIL).

For languages that are essentially just syntatic variants of each other (e.g. C# vs. VB.NET) then I wouldn't expect there to be much difference. But if the languages are too divergent (e.g. C# vs. F#) then you can't really make a valid comparison because you can't really write two "equivalent" non-trivial code samples in both languages anyway.

Dean Harding
I think you have made a good point there about "comparing" equivalent code. Its the problem I am at now. I can do simple tests to see the output and work through it, but complex code is much more tricky. So far F# looks good.
WeNeedAnswers
A: 

The language can just be thought of as the "front-end" to the IL code, so the only difference between the languages is whether the compiler will produce the same IL code or less/more efficient code.

From most of what I've read online it seems as though the managed C++ compiler does the best job of optimizing the IL code, although I haven't seen anything that shows a remarkable difference between the main languages C#/C++/VB.NET.

You could even try compiling the following into IL and take a look!?

F#

#light
open System
printfn "Hello, World!\n"
Console.ReadKey(true)

C#

// Hello1.cs
public class Hello1
{
    public static void Main()
    {
        System.Console.WriteLine("Hello, World!");
        System.Console.ReadKey(true);
    }
}
Siyfion
Using the same base constructs using VB,C# or C++, I would expect the code generated to be equivalent as they are all very similar (maybe VB has some esoteric stuff depending on which mode it has been developed in). But F# as @codeka mentions in his post is hard to compare.
WeNeedAnswers
Agreed, the way that F# is interpreted makes it almost impossible to write anything *but* a very trivial test, like the one above. Still, looking at the IL code generated for each is quite interesting.
Siyfion
+7  A: 

First of all, the wide range of languages on the .NET platform definitely contains languages that generate code with different performance, so not all languages are equally performant. They all compile to the same intermediate language (IL), but the generated code may be different, some languages may rely on Reflection or dynamic language runtime (DLR) etc.

However, it is true that the BCL (and other libraries used by the languages) will have the same performance regardless of what language do you call them from - this means that if you use some library that does expensive calculations or rendering without doing complex calculations yourself, it doesn't really matter which language you use to call it.

I think the best way to think about the problem is not to think about languages, but about different features and styles of programming available in those languages. The following lists some of them:

  • Unsafe code: You can use unsafe code in C++/CLI and to some point also in C#. This is probably the most efficent way to write certain operations, but you loose some safety guarantees.

  • Statically typed, imperative: This is the usual style of programming in C# and VB.Net, but you can also use imperative style from F#. Notably, many tail-recursive functions are compiled to statically typed, imperative IL code, so this also applies to some F# functions

  • Statically typed, functional: This is used by most F# programs. The generated code is largely different than what imperative category uses, but it is still statically typed, so there is no significant performance loss. Comparing imperative and functional is somewhat difficult as the optimal implementation looks quite different in both of the versions.

  • Dynamically typed: Languages like IronPython and IronRuby use dynamic language runtime, which implements dynamic method calls etc. This is somewhat slower than statically typed code (but DLR is optimized in many ways). Note that code written using C# 4.0 dynamic also falls into this category.

There are many other languages that may not fall into any of these categoires, however I believe that the above list covers most of the common cases (and definitely covers all Microsoft languages).

Tomas Petricek
The underlying architecture must be considered though when developing a language against it. Look at the problems that cPython has had with the GIL, all stemmed from the use of C. Those 1960's Lispers and their lisp machines were on to something :)
WeNeedAnswers
+4  A: 

I'm sure that there are scenarios where idiomatic code is slightly more performant when written in one .NET language than another. However, stepping back a bit, why does it matter? Do you have a performance target in mind? Even within a single language there are often choices which you can make that affect performance, and you will sometimes need to trade performance off against maintainability or development time. If you don't have a target for what constitutes acceptable performance, then it's impossible to evaluate whether any performance differences between languages are meaningful or negligible.

Additionally, compilers evolve, so what's true of the relative performance today won't necessarily hold going forward. And the JIT compiler is evolving too. Even processor designs are variable and evolving, so the same JITTed native code can perform differently across processors with different cache hierarchies, pipeline sizes, branch prediction, etc.

Having said all of that, there are probably a few broad rules that largely hold true:

  1. Algorithm differences are probably going to make a bigger difference than compiler differences (at least when comparing statically typed languages running on the CLR)
  2. For problems which can be parallelized easily, languages which make it easy to take advantage of multiple processors/cores will provide a simple way to speed up your code.
kvb