Whilst writing our FFT implementation in both C# and F#:
I noticed several interesting things.
Firstly, C# doesn't provide a type for complex numbers. So you must either pull in a random library or write your own. I think that is a bit of a shame because Microsoft have clearly put a lot of effort into creating a high-performance .NET implementation and lots of people are clearly interested in writing numerical programs in .NET.
Secondly, when you define your own complex number type you have the choice between using a struct and using a class. The difference between the two is essentially that C# will pass a struct by value and a class by reference. The tradition in languages like C++ and C# is to use structs and unbox agressively yourself where possible, with the belief that structs are often faster.
I thought I'd tinker with this because my first F# implementation was 3x slower than my first C# implementation and I remembered that the complex number implementation in the F# standard library still uses a class (structs were only added to F# recently).
Sure enough, reimplementing the complex class in F# with a struct-based version brought the speed up to par, actually slightly faster than the C#.
This was the first of two interesting performance results. The whole program was made 3x faster simply by using a struct rather than a class. Another point for the faith-based view that structs are fast and well suited to atomic values.
Then I tried a similar experiment on our 2D and 3D vector graphics software:
changing the implementation of 2D and 3D vectors to structs. Surprisingly, although I had assumed that low-dimensional vectors have almost identical usage to complex numbers, using a struct is actually ~15% slower. Not a huge performance difference but an interesting result nonetheless.
So structs are not always faster, even for very simple types, and there is no substitute for benchmarking.
I should note that there are more differences between structs and classes in the context of C# because this language exposes more complicated argument passing semantics (value and reference types).
Background reading on the reference counting vs tracing garbage collection debate - Eight years ago I answered a question on Stack Overflow about the suitability of OCaml and Haskell for soft real-time work like visualization: "*for real-ti...
5 months ago