tabs ↹ over ␣ ␣ ␣ spaces

by Jiří {x2} Činčura

Improving list sum function based on head and tail with C# 8

3 Mar 2020 3 mins C#, Functional programming

Some time back I wrote about Head- and Tail-like methods in C# (and F# and Python and Haskell). For some strange reasons I came across the Sum method I wrote there and I thought maybe I can rewrite it with switch expression now available in C# and have a nicer looking code. I mean I’m a big fan of succinct (yet still readable) code. But I had no idea what a journey it will be.

Let me start by putting the Sum method here so we have it in from of our eyes.

int Sum(List<int> list)
{
	switch (list.Count)
	{
		case 0:
			return 0;
		default:
			var (head, tail) = list;
			return head + Sum(tail);
	}
}

Fairly simple, right? Shouldn’t be difficult to rewrite it using the switch expression. Err. The default clause contains a block and not an expression. Something like this is not going to go through the C# compiler.

int Sum(List<int> list) => list.Count switch
{
	0 => 0,
	_ =>
	{
		var (head, tail) = list;
		return head + Sum(tail);
	},
};

I can probably use local functions and work around it.

int Sum(List<int> list)
{
	static int SumImpl(List<int> list)
	{
		var (head, tail) = list;
		return head + Sum(tail);
	}
	return list.Count switch
	{
		0 => 0,
		_ => SumImpl(list),
	};
}

And although this works, I don’t think I made the code nicer or succinct at all. In fact, I think it’s tangled compared to the original version. The problem is the tuple deconstruction and the fact that I can’t put it into expression (Maybe you can?).

Something like the following would be nice, but again I don’t think it’s helping the code and I’m just trying to free myself on top of previous limitations.

int Sum(List<int> list)
{
	static int SumImpl(List<int> list) => SumSum(((head, tail) = list));
	static int SumSum((int head, List<int> tail) item) => item.head + Sum(item.tail);
	return list.Count switch
	{
		0 => 0,
		_ => SumImpl(list),
	};
}

It’s time to think outside the box. And then it hit me. I can probably go one step higher and work from there. Because then I can use var declarations in the cases.

int Sum(List<int> list) => list switch
{
	var l when l.Count == 0 => 0,
	var (head, tail) => head + Sum(tail),
};

Not sure if it’s more readable, but it’s succinct. Expression body, check; switch expression check. The only problem I have is the first clause. It’s kind of weird, isn’t it? I can probably improve it by not introducing a new variable.

int Sum(List<int> list) => list switch
{
	var _ when list.Count == 0 => 0,
	var (head, tail) => head + Sum(tail),
};

That’s slightly better. But still, meh.

And then I saw it! The property pattern is going to help me be more declarative.

int Sum(List<int> list) => list switch
{
	{ Count: 0 } => 0,
	var (head, tail) => head + Sum(tail),
};

I am happy with it. I think this is as good as it gets right now. Or is it?

Profile Picture Jiří Činčura is .NET, C# and Firebird expert. He focuses on data and business layers, language constructs, parallelism, databases and performance. For almost two decades he contributes to open-source, i.e. FirebirdClient. He works as a senior software engineer for Microsoft. Frequent speaker and blogger at www.tabsoverspaces.com.