On Type Inference

This is a comment I recently saw on a headline-grabbing article about Swift: –

I also don’t think that “type inferring” is of great use. If you cannot be bothered to hack in a variable’s data type, maybe you should not develop software in the first place.

I was so infuriated by this comment that I ended up writing this blog post. The thing that infuriated me so much was more the arrogance of the second sentence as much as the ignorance of why having type inference can be such a massive productivity gain.

Here are three versions of the same sentence written in three different ways – slightly contrived as usual to make my point…

  • Hello, I’m Java. I have a bag of apples. In this bag of apples there are five apples.
  • Hello, I’m C# 3. I have a big of apples that has five apples in it.
  • Hello, I’m F#. I have a bag of five apples.

These statements don’t actually translate directly to code but you get the idea. Why would you need to write out the above sentence in either of the latter ways? Are you learning the language from a school textbook? Or using it in a professional & fluent manner?

C# can declare locally-scope implict variables and create implicit arrays. F# can do full H-M type inference. Java can’t do much of anything really. Here’s the above sentences sort of written as code (the final example uses the same C#-style syntax to keep things consistent): –

The latter example is more in the F# vein, without braces, or keywords whose usage can be inferred.

The real power of type inference comes from the ability to chain multiple functions together in a succinct manner, and then at some point in the future changing the type of one of those functions and not having to change any type signatures of dependent functions. It’s quite addictive, and once you get used to it it’s quite difficult to go back to an explicitly-typed language.

Last minute update: It turns out that the individual who I quoted above at the start of this post had confused type inference with dynamic typing. I suspect that this won’t the first or last person who has done this.

The future of C#

Having recently discussed (and effectively ruled out) JavaScript as a valid programming language on the server, I wanted to review the current situation for C#, how it has changed in the past few years and my thoughts on where I see it going as a server-side language.

Java and C#

I want to start by first doing a quick comparison between languages on the JVM and .NET. The main differentiators that I see between the JVM and .NET are twofold: –

The JVM is much more common on non-Windows servers e.g. LAMP stacks. Yes, there’s Mono, which is becoming more popular, but generally this domain is taken by Java. Between the two most popular languages across the two platforms – Java and C# – Java has slowly stagnated over the years, caused apparently by over-deliberating by committee on details of various features whilst C# has gone steaming ahead and introduced genuinely revolutionary features to OO developers such as queries and asynchronous programming as first class citizens, and also functional programming constructs.

Whilst Java (and indeed the JVM) has a fundamentally limited implementation of generics which will likely never change, C# and .NET have generics baked throughout the runtime. Whilst Java 8 will (in 2014) finally get lambda expressions (something which I remember Java developers passionately castigating in 2008 when C#3 first came out), again, because it doesn’t have a notion of a delegate, it won’t be as elegant as the C# implementation, involving (as I understand it) compiler tricks to turn lambdas into single method interfaces.

One thing both Java and C# do have in common is that they are rapidly becoming languages that will be prevalent on the server-side, notwithstanding e.g. internal LOB applications or native mobile applications (even that’s a bit of a hot potato with things like Xamarin – maybe best left for a discussion on another day).

The good, the bad and the ugly of C#

So C# has given us developers some pretty good things. Yet in a sense, since C#3 came out, the language hasn’t moved forward that much. Dynamic was introduced, we got better co- and contra-variance, and C#5 introduced async/await. All excellent features (particularly the last one), but where do we go from here? I’ll go back to my comment about lambda expressions on Java again here. Some of the main criticisms of LINQ when it first came out by the Java community were driven by emotion rather than rationale – that LINQ was just a poor man’s SQL embedded into the language; that C# was now a dynamic language; that extension methods would somehow break encapsulation; that LINQ was just Microsoft’s latest attempt to get new customers and it “wouldn’t work” etc. etc. All nonsense, yet one underlying message from the complaints was that lambdas and LINQ would be too confusing for developers. To an extent I think that this is more of an issue in the Java community, where I see the language being far more OO than C# is nowadays.

But, at the same time, think about a new developer learning C#. There are already many ways to achieve the same thing at both the language and framework level e.g. set based operations, asynchronous operations, multi-threading etc. etc.. Think how many constructs and fundamentals that there are to learn these days; you’d probably get contradictory information and advice from ten experienced .NET developers that have picked up different bits over the years. At least we’ve been drip-fed C# over the years at a rate we can absorb 🙂 whereas a new developer will have to try to distil that information to a manageable amount. It’s harder and harder to know the “right” way of doing things.

There are some things in the language that we’ll probably never get – things like non-nullable reference types, which would eliminate whole classes of bugs, or the removal of leftovers from .NET 1 that were replaced in .NET 2 like non-generic collections etc., or the multiple-ways-to-do-async etc. etc.

C# vNext

Where does C# go from here? Do the designers continue to add features to it e.g. immutability / more succinct type declarations (something I’ve been hearing might well happen) / improved type inference (something I would love to see)? As each revision of C# goes in, it becomes harder and harder to add new features to it. On the other hand, languages like Scala on the JVM and F# on the .NET framework are changing at a much more rapid pace. Ironically, Scala, to me, seems to me more like C# than F# with its objects-first-but-functional-programming-supported approach, but both it and F# are introducing features to their respective communities.

Is there a case to perhaps keep the changes in C# at a relatively sedate pace now, before it becomes even more complex, and let e.g. F# push the boundaries with new features? What features do we need to see added to C# to improve the programming experience without making the language a mish-mash? Added to this is Rosyln – what impact will that have on the language going forward?

I suppose the main upshot is that I think the days of mega-changes in C#, like we saw in C#3, are over. What I suspect we’ll see in the future are most likely carefully-thought-out smaller features which can improve the experience or perhaps deal with specific problem domains but won’t necessarily change the fundamentals of C# as we saw with LINQ.

What makes a .NET developer?

An experienced Java developer colleague of mine has recently transferred into a .NET based team. He asked me, aside from the obvious things like reading up on the differences between C# and Java and getting a reference book or two on parts of .NET, what are the common practices or attitudes of .NET developers? How do they differ from your typical Java developer?

I think it’s a great question, and it got me wondering – what are the typical behaviours of a .NET developer? What qualities (or lack of!) characterise the average .NET developer? So having worked with quite a few .NET developers in the last decade, I thought I’d share my thoughts on how I see as what the average .NET developer is like, in terms of skills and attitudes.

The attributes of a .NET Developer

Before I jump in, I should point out that firstly, my experiences might not reflect what you have seen; and secondly, that this is what I have seen of a “typical” .NET developer that has some experience – but there are definitely those that I have worked with that did not fit the profile below.

Design Patterns

The average .NET developer – let’s call him Bob – generally does not have a great grasp of the GoF design patterns. He may actually use some of them day-to-day, but without realising the application to a proper design pattern. He knows the names of two or three popular patterns such as Factory and Singleton, but often struggles to actually identify opportunities to apply them in a real-world scenario.

Deep Understanding

Bob sees himself as a client of the services offered by Visual Studio and the .NET framework, and sees little reason to understand why things work the way that they do. This includes the C# compiler, code generation features of Visual Studio, and the classes in the framework itself. This is by no means a bad thing – after all, these things are there to provide services to the developer – but there is often a real lack of understanding with what’s going on under the hood. Situations such as these might be applicable to Bob: –

  • Bob compiles lots of code every day, but might not know the process of what happens in order to make an executable program.
  • Bob uses foreach loops all the time, but does not know how they relate to IEnumerable.
  • Bob loves LINQ, but does not know what deferred execution is, or how query operators relate to extension methods.
  • Bob loves Entity Framework 4, but does not know what IQueryable is.
  • He uses List<T> all the time – but has no idea how to write his own generic classes.

Now, the sort of thing above that I’m talking about is not referring to being able to describe the lines of C# and IL that are generated when you use the “yield” keyword – but to at least have an understanding of how state machines fit in with it.

Test Driven Development

Bob has heard of TDD, and thinks it sounds like a great idea, but for the time it would take to apply it. He might even write unit tests from time to time. However, he is not experienced in the art of writing AAA unit tests, or in understanding the difference between testing a single class rather than writing an integration test which cuts across multiple tiers. He might use unit tests, but does not have enough confidence in them to rely on them – so he still wants to manually test the same bit of code out in the debugger as well from time to time.

Code Generation

Bob is happy to use code generation tools that he is aware of in order to rapidly fulfil business requirements, such as the Windows Forms designer, or the RIA Services domain service generator – IMHO a good thing. But he sees these things as tools without wanting to know what it does behind the scenes. What code does it generate? At the same time, he will often be content to write reams of boilerplate code manually rather than create a code generation tool himself, or to ask whether there is another tool out there that will do the job for him.

The Commercial Reality

Bob will sometimes see the importance of writing high quality, maintainable code as an optional nice-to-have in the quest to meet tight deadlines and timescales. He will often prefer the short-term goal of achieving the business requirement of today than building one that can more quickly deliver the dozen business requirements that must be delivered by the end of next week.

Why is this?

The above may sound unfair to many developers. After all, if you’re able to write software today in such a manner, what’s the problem? Well, for one, you could be doing the same thing in much less time, and therefore delivering far better value to your client / company.

Years ago the average C++ developer could not get by without a knowledge of what a pointer is, or what malloc() does, or how to write an efficient sort algorithm. Nowadays the barriers to entry in the world of .NET are much lower. In itself this is a good thing – anything that makes it easier to code by getting rid of having to write boilerplate code gets a thumbs up from me. But it’s also important that we as developers understand the “how things happen” as well as the “what they do”.

Professional development is still, to my mind, a highly skilled trade that we are constantly learning about, and we need to remember that just because we can easily write an application that can communicate over a network, save to a database, give error handling etc. with relative ease, it doesn’t mean that we can or should forget what’s going on behind the scenes.

Flame away…