AutoProperties, Structs and Constructors (C# Wishes Part 3)

I’m sure most of us have been there. You have some small data type to declare, which only really contains a couple of primitives and is clearly most appropriate to exist as a struct. You put a couple of values in it, and because you’re doing this quickly and you want your code to be simple, you use auto properties. For this kind of struct there’s (hopefully) no reason not to.

And in the best traditions of those cookery programmes you see on tv, here’s one that I prepared earlier: Ta-da!

public struct PolarCoord
{
	public double R { get; set; }
	public double Theta { get; set;}
}

This will certainly work, and it will compile, but it’s a bit too rough’n’ready. It gives no way of constructing and initializing a PolarCoord at the same time, which is not really nice for consuming your snazzy new struct. Besides, there are issues with mutable structs. Let’s be good coders and fix those problems.

public struct PolarCoord
{
	public double R { get; private set; }
	public double Theta { get; private set; }

	public PolarCoord(double r, double theta)
	{
		this.R = r;
		this.Theta = theta;
	}
}

This looks much better.

But hit F5 and surprise, surprise, PolarCoord no longer compiles:

Xmas-CSh-Wishes-Pt3-CompilerError

The problem is – roughly speaking – that the compiler doesn’t realize that the property initialization in the constructor is really no different in practice from initializing the fields, and so it thinks (incorrectly) that you might be mis-using an uninitialized struct.

There is a workaround. You can make the code compile by inserting an explicit call to the base constructor. Like this:

public PolarCoord(double r, double theta) : this()
{
	this.R = r;
	this.Theta = theta;
}

Doing this is not ideal. There’s an (admittedly tiny) performance hit. That call to the base constructor will consume CPU cycles uselessly initializing the fields to zero immediately before you overwrite them with the actual values. And it’s also made your code a bit more complicated than it needs to be. Generally you don’t expect to have to call default constructors from other constructors unless the default constructor is doing something useful, which in this case is plainly not the case. Plus the first time you encountered the problem, it probably wasted five minutes of your time while you googled for the solution.

But let’s step back a moment. This is arguably one of the most unnecessary errors the C# compiler produces. The thing is, if the compiler was a tiny bit more intelligent in this situation, there would be no need for this to error out. It’s perfectly obvious what your intentions are. You want to initialise the backing fields, but because they are auto-properties, the only way to do that is to call the property setters. It should be almost trivial for the compiler in this situation to solve the problem – for example by rewriting the code under the hood to set the backing field directly. The situation where it needs to do this is very well-defined: Setting an auto-property in the constructor of a struct. And heck, the compiler does much more complicated code substitutions every time you write a foreach loop. And I don’t even want to think about what code rewrites the compiler has to do every time you write a LINQ query expression. By comparison, rewriting to fix this issue is nothing.

So yes – if you haven’t already guessed – the third item on my C# wish list is… (And I know the title of this article kind-of gives it away, so it’s not too hard to figure it out) for Microsoft to fix auto-properties to work properly in constructors of structs. It’s a tiny, tiny change to C# that would fix a minor but incredibly annoying niggling problem. And, just like my previous C# wish request, it would go some way to make auto-properties a bit more useful (or, depending on your point of view, less useless).

Advertisements

Comment on this article (your first comment on TechieSimon will be moderated)

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s