All posts by Thomas Zeman

Give your async lambda type the right name

The BCL has well-known delegate types representing synchronous invocation signatures: Action<> and Func<>. But what about asynchronous methods? An asynchronous method with no return value translates to Func<Task>. That looks kind of strange because usually Func means a function with a return value but actually all we are getting is a Promise that the operation will complete without a result. A task amplifies (or let’s say wraps) a result (or void) but instead of having an asynchronous construct which handles the result directly, Task and result are treated as one unit as part of a synchronous call.

The following table shows the synchronous types and how you have to specialize them to get asynchronous versions:

WhatSynchronousAsynchronous w. BCL
no argument and no resultActionFunc<Task>
one argument and no resultAction<T>Func<T, Task>
no argument but resultFunc<TResult>Func<Task<TResult>>
one argument and resultFunc<T,TResult>Func<T,Task<TResult>>

This leads to code like this:

// Sample asynchronous method which takes
// no parameter and returns no result (Func<Task>)
public async Task DoAsync()
{
await Task.Delay(42); // pretend we do something
}

// Method calling asynchronous lambda
public async Task CallAsync(Func<Task> func)
{
await func();
}

public async Task Orchestrate()
{
Func<Task> func = () => DoAsync();
await CallAsync(func);
}

As said at the beginning, I think especially for people who are not so firm in asynchronous programming it becomes confusing that Func<T> actually represents a function with no parameters and no return value. Even for advanced programmers this is something they constantly have to have in their mind when reading code. Therefore, I believe generic asynchronous delegate types are missing in the BCL and should be part of every project with asynchronous code. The following definitions tackle this problem:

Proposed asynchronous typesDefinition of asynchronous types
AsyncActiondelegate Task AsyncAction();
AsyncAction<T>delegate Task AsyncAction<in T>(T arg);
AsyncFunc<TResult>delegate Task<TResult> AsyncFunc<out TResult>();
AsyncFunc<T,TResult>delegate Task<TResult> AsyncFunc<in T, out TResult>(T arg);
// Sample asynchronous method which takes no
// parameter and returns no result (AsyncAction)
public async Task DoAsync()
{
await Task.Delay(42); // pretend we do something
}

// Method calling asynchronous lambda
public async Task CallAsync(AsyncAction action)
{
await action();
}

public async Task Orchestrate()
{
AsyncAction action = () => DoAsync();
await CallAsync(action);
}

Beside being easier to read this also supports better recognition of what is a command and what is a query in your code (referring to CQRS in Wiki or Fowler )

Flattr this!

Order of Magnitude

I am a big fan of Carlo Pescio’s work on the Physics of Software and his way of discovering analogies in software for physical terms like force or friction. Looking at a large code base by myself every day, I could not help it and started to develop my own ideas about the structure of software code in general. What is the natural logic behind it? In the following few posts I will summarize my thoughts on this.

This first one is about a general observation: We, humans, tend to invent different names for things that are just a different order of magnitude of the same type of thing. For example when you think about places where people live together, we know a hamlet, village, town, suburb, city or metropolis. These are different words but describe the same characteristics for a place: The amount of people living there. Of course, a city is more than just a dozen joint hamlets when you consider for example available public infrastructure. However, this is a result of the size and history of the place and does not come with their descriptive. Sydney and Berlin are both a metropolis but Sydney does not have a subway whereas Berlin does.

Another example is the wording for the size of a group of soldiers: Corps, Brigade, Division, Battalion, Regiment, Company. While most people know these terms they leave a lot of room for ambiguity because except people close to the military hardly anyone knows how many soldiers a division really comprises. Contrary to having names for different levels in a hierachy (or orders of magnitude) it sound reasonable to simply number them:

AmountCodeRelates to
1-99PL1Hamlet
100-999PL2Village
1.000-9.999PL3Town
10.000-99.999PL4City
100.000-999.999PL5Larger City
1.000.000-999.999.999PL6Metropolis

So instead of talking about a “Hamlet” or “Metropolis” we could use the codes “PL1” or “PL6” which leave no room for interpretation and foster clear communication. By the way, something that has also been put into place by the NATO to describe the rank of an army officer (sharing properties of power or responsibility) – again with the goal to provide a common language for all the different ranks existing in their respective member countries. See: Nato Ranks

Another example where this idea was applied are the different levels of a CPU cache. They could have been called something like “brisk cache” or “sedate cache” but are actually just numbered: L1, L2, L3 cache. Foster clear communications.

Unfortunately when it comes to the structure of software it’s very common to talk about things like: Block, Class, Component, Bundle, Module, Building Block, Assembly, Package, Subsystem, Container, Program, System but what e.g. a “Module” or “Component” really means heavily depends on the idea and picture individuals communicating with each other have.

Flattr this!