Phillip Trelford's Array

POKE 36879,255

Has C# Peaked?

Microsoft’s C# programming language first appeared in 2000, over 15 years ago, that’s a long time in tech.

Every month or so there’s a “Leaving .Net” articles, the last one I bumped into was “The collapse of the .net ecosystem” from Justin Angel:


The article shows, through a series of charts, the level of interest in C# peaking and then falling.

This is what I’d consider to be the natural continuum of things, where languages have their day, and then slowly decline. In the past C was my primary language, then C++ and so on, why should C# be any different?

Disclaimer: This is not a leaving .Net post, just some of my own research that I thought I’d share, with a focus on the UK as that’s where I live.

Job trends

Indeed.com provides statistics on job placements with specific keywords, lets look at C#:

csharp jobgraph

This chart appears to show job adverts peaking between around 2010 and 2012 and tapering off fairly heavily after that.

Google trends

Google trends lets you track interest over time based on a keyword, here I'm looking at C# in the UK:


On this chart the peak seems to be earlier, around 2009, perhaps the trend can be seen earlier in the UK, but again the decline in interest is clearly visible.

TIOBE

Questions around the validity of TIOBE’s numbers abound, but here it is anyway:

TIOBE Index for CSharp

Here the peak appears to be around 2012, although the drop is perhaps less pronounced.

PYPL

Yet another popularity index this time tracking google trends for “C# tutorial” in the UK:

PYPL CSharp UK

This chart shows uses a logarithmic scale, however what we might surmise, if the numbers are to believed, is that interest in C# appears to fall off a cliff towards the end of 2014.

Stack Overflow

The recent stackoverflow developer survey also shows a significant decline in interest from 44.7% in 2013 to 31.6% in 2015. Developer’s current preferences are also quite revealing:

image

 

Where’s everyone gone?

This is only conjecture, but from my experience of .Net oriented developer events over the years in the UK, C# has always had a significant focus on the web and ASP.Net. My suspicion is that with the rise of thick-client JavaScript and mobile, significant numbers of developers have been migrating naturally towards those ecosystems.

Should I panic?

Probably not, there’s still plenty of C# jobs out there for now, and hell, some of the best paid jobs nowadays are for maintaining C++ and even COBOL systems. But if the numbers are anything to go by then we can say that C# interest has peaked.

That said who knows what the future will hold and perhaps like C++ there’ll be a renaissance in the future, although C++’s renaissance never really brought it back to the levels of it’s heady hey days.

Then again perhaps it’s more pragmatic not to dwell too heavily on the past, accept the numbers, and look to a new future. If you’re skills extend beyond one language then I guess you’ve probably got nothing to worry about, otherwise perhaps it’s time to pick up a new language and new paradigms.

And I’ll leave you with a question: Do you think you’ll be using the same programming language in 5 years time?

A Fistful of Dollars

Just over a week ago I took the Eurostar over to Paris for NCrafts, a conference bringing together over 300 software craftsmen and craftswomen:

The event was held in a crypt and featured a good number of F# sessions:

Mathias Brandewinder gave an excellent closing talk on The T in TDD : tests, types, tales.

 NCrafts 2015 - May 2015

In this live coding session, Mathias took the multi-currency money example from Kent Beck’s seminal Test-Driven Development by Example book. First implementing a dollars class in C# driven by a unit test for quick feedback and then contrasting it with a similar implementation in F# using the REPL for immediate feedback.

Unit Test

The system needs to be able to multiply a price in dollars by a number of shares, so that 5 USD * 2 = 10 USD:

public class Tests
{
   [Test]
   public void five_dollars_times_two_should_equal_ten_dollars()
   {
      // arrange
      var five = new Dollars(5);
      // act
      var result = five.Times(2);
      // assert
      Assert.AreEqual(new Dollars(10), result);
   }
}

C# Dollars

Based on the test an immutable dollars class can be implemented:

public class Dollars
{
   private readonly decimal _amount;

   public Dollars(decimal value)
   {
      _amount = value;
   }

   public decimal Amount
   {
      get { return _amount; }  
   }

   public Dollars Times(decimal multiplier)
   {
      return new Dollars(this._amount * multiplier);
   }
}

The code now compiles, but the test fails!

C# Equality

The test fails because in C# class types use reference equality, so we must override Equals:

public class Dollars
{
   private readonly decimal _amount;

   public Dollars(decimal value)
   {
      _amount = value;
   }

   public decimal Amount
   {
      get { return _amount; }  
   }

   public Dollars Times(decimal multiplier)
   {
      return new Dollars(this._amount * multiplier);
   }

   public override bool Equals(object obj)
   {
      var that = obj as Dollars;
      return
         that != null
         ? this.Amount == that.Amount
         : false;
   }
}

Note: at this point FXCop will also recommend that we implement GetHashCode as we’ve implemented Equals.

F# Dollars

In F#, the simplest thing that could possibly work is a measure type which gives compile time type safety:

[<Measure>] type usd

5.0M<usd> * 2.0M = 10.0M<usd>

We can also test it immediately in F# Interactive as above, or alternatively write a unit test as below:

let [<Test>] ``5 USD * 2 = 10 USD`` () =
   Assert.AreEqual(10M<usd>, 5M<usd> * 2M)

Note: F# units of measure are erased at compile time meaning there’s no runtime performance penalty.

F# Money

For a report we’d probably want to encode money dynamically with a currency component. Below I’ve chosen an F# record type:

type Money = { Amount:decimal; Currency:string } with
   member this.Times(multiplier) = { this with Amount = this.Amount * multiplier }

let USD amount = { Amount=amount; Currency="USD" }

USD 10M = (USD 5M).Times(2M)

This succeeds immediately as F# implements equality (and GetHashCode) by default for us on record types.

Unquote

As an aside, I find assertions over numerical types are more natural using the Unquote library which lets you assert equality using the equals operator, i.e.

let [<Test>] ``5 USD * 2 = 10 USD`` () =
   test <@ (USD 5M).Times(2M) = USD 10M @>

Summary

When writing code we may seek quick feedback on our first implementations. In C# we’d typically write reflection based unit tests to get early feedback, in F# we may use F# interactive first for immediate feedback and later promote useful tests to reflection based tests that run as part of our continuous build and may help find regressions.

Also in this scenario implementing types in F# required a lot less boilerplate than the equivalent C# code.

String and StringBuilder revisited

I came across a topical .Net article by Dave M Bush published towards the tail end of 2014 entitled String and StringBuilder where he correctly asserts that .Net’s built-in string type are reference types and immutable. All good so far.

The next assertion is that StringBuilder will be faster than simple string concatenation when adding more than 3 strings together, which is probably a pretty good guess, but lets put it to the test with 4 strings.

The test can be performed easily using F# interactive (built-in to Visual Studio) with the #time directive:

open System.Text

#time

let a = "abc"
let b = "efg"
let c = "hij"
let d = "klm"

for i = 1 to 1000000 do
   let e = StringBuilder(a)
   let f = e.Append(b).Append(c).Append(d).ToString() 
   ()
// Real: 00:00:00.317, CPU: 00:00:00.343, GC gen0: 101, gen1: 0, gen2: 0
   
for i = 1 to 1000000 do
   let e = System.String.Concat(a,b,c,d)
   ()
// Real: 00:00:00.148, CPU: 00:00:00.156, GC gen0: 36, gen1: 0, gen2: 0

What we actually see is that for concatenating 4 strings StringBuilder takes twice as long as using String.Concat (on this run 0.317ms vs 0.148ms) and generates approximately 3 times as much garbage (gen0: 101 vs gen0: 36)!

Underneath the hood the StringBuilder is creating an array to append the strings into. When appending if the current buffer length is exceeded (the default is 16) then a new array must be created. When ToString is called it may, based on a heuristic, decide to return the builder’s array or allocate a new array and copy the value into that. Therefore the performance of StringBuilder is dependent on the initial capacity of the builder and the number and lengths of the strings to append.

In contrast, String.Concat (which the compiler resolves the ‘+’ operator to) calculates the length of the concatenated string from the lengths of the passed in strings, then allocates a string of the required size and copies the values in, ergo, in many scenarios it will require less copying and less allocation.

When concatenating 2, 3 or 4 strings we can take advantage of String.Concat’s optimized overloads, after this the picture changes as an array argument must be passed which requires an additional allocation. However String.Concat may still be faster than StringBuilder in some scenarios where the builder requires multiple reallocations.

But wait there’s more, going back to the ‘+’ operator, if we assign the integer literal expression 1 + 2 + 3 the compiler can reduce the value to 6, equally if we define the strings as const string then the compiler can apply the string concatenations at compile time leading to, in this contrived example, no cost whatsoever.

The moral of the story is when it comes to performance optimization - measure, measure, measure.