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 an independent developer focusing on data and business layers, language constructs, parallelism and databases. Specifically Entity Framework, asynchronous and parallel programming, cloud and Azure. He's Microsoft Most Valuable Professional and you can read his articles, guides, tips and tricks at www.tabsoverspaces.com.