Saturday, 21 January 2023

C# Functional Project - Unit

Functional programming relies upon the ability to combine functions. This can be achieved in C# using the Func delegate. However, the Func delegate only works for functions that return a value and not void. Void is not a value, and, so a different mechanism is required. C# uses the Action delegate. To create a uniform experience it is useful to introduce a type that indicates a function performs and action/command rather than a query.

Top

In this post...

Top

Command Versus Queries

It is probably fair to say that most software applications consist of commands and queries. As one might expect a command modifies the state of a program. A query, asks for data without modifying the program state.

Top

Commands

Delving a little deeper, a command performs one or more tasks to complete a issued command. Generally, it makes no sense to return a value, (bar error information). Commands include creating/updating database records, writing to a log file, writing to a file and so. In C# a function/method that returns nothing specifies its return "type" as void.

Top

Queries

Where a command does not return a value, a query always returns a value. One would also hope that calling the same function, with the same input value would always yield the same, exact results. As a ridiculous example, consider the following function...

int Add4(int input)
{
  return input + 4;
}

If I call the Add4 function with 6, I would expect a return value of 10. If I call the same function, 6 months later, after perfoming code updates, with the same parameter, 6, I WOULD still expect to receive a value of 10.

Top

The Unit Type

OK, some might be asking. What does any of this have to with a new type, namely Unit. The answer is surprisingly simple. We need functions to return a value so that functions can be combined/chained. Currently, for functions returning void, one must use The Action delegate, for functions returning a value, the Func delegate is used. Trying to combine Actions and Funcs, is possible, but is far from intuitive.

You can return anything as a Unit type. The key is to be consistent. You could, for example, simply return an integer, say zero. To offer more type safety, I declare Unit as follows...

public static partial class Fun
{
  public readonly struct Unit
  {
  }

  public static readonly Unit unit = new Unit();
}
Top

Using the Unit Type

To use the Unit type simply ensure commands that normally return a void now return a unit. Assume I have the following method...

public void UpdateUser(User user)
{
  // perform some action here
}

The above code should be modified to return the Unit type...

public Unit UpdateUser(User user)
{
  // perform some action here
  return unit;
}

Notice the case difference. The function declaration specifies Unit as the return type. The function body returns unit (lowercase), i.e. an instance of the Unit type.

Top Top

No comments:

Post a Comment