771 words
4 minutes
Understanding C# Features (7) Higher-Order Function

[LINQ via C#] - [C# Features]

Function as input/output#

Higher-order function is a function taking one or more function parameters as input, or returning a function as output. The other functions are called first-order functions. (Again, in C#, the term function and the term method are identical.) C# supports higher-order function from the beginning, since a C# function can use almost anything as its input/output, except:

  • Static types, like System.Convert, System.Math, etc., because there cannot be a value (instance) of a static type.
  • Special types in .NET framework, like System.Void.

A first-order function can take some data value as input and output:

public class DataType { }
public static DataType FirstOrder(DataType dataValue)
{
return dataValue;
}
public static void CallFirstOrder()
{
DataType inputValue = default(DataType);
DataType outputValue = FirstOrder(inputValue);
}

To get a higher-order function, just replace above DataType/dataValue with a function type/function value. In C#, delegate type can be viewed as function type, and delegate instance can be viewed as function value (instance). So:

public delegate void FunctionType();
public static FunctionType HigherOrder(FunctionType functionValue)
{
return functionValue;
}
public static void CallHigherOrder()
{
FunctionType inputValue = default(FunctionType);
FunctionType outputValue = HigherOrder(inputValue);
}

Above HigherOrder becomes a higher-order function takes function as input and output.

Besides named function, anonymous first-order/higher-order functions can be easily expressed with lambda expression:

public static partial class HigherOrderFunction
{
public static void Lambda()
{
Action firstOrder1 = () => { };
Action<Action> higherOrder1 = action => action();
Func<int> firstOrder2 = () => default(int);
Func<Func<int>> higherOrder2 = () => firstOrder2;
}
}

Higher-order functions are everywhere in .NET framework, like fore mentioned Sort method of List. It’s signature is:

namespace System.Collections.Generic
{
public class List<T>
{
public void Sort(Comparison<T> comparison);
}
}

Its comparison parameter is a function value of Comparison function type:

namespace System
{
public delegate int Comparison<in T>(T x, T y);
}

Most LINQ query methods are higher-order functions, like Where. Its signature is:

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);

Its predicate parameter is a function value of function type Func<TSource, bool>:

public static partial class LinqToObjects
{
public static IEnumerable<int> Positive(IEnumerable<int> source)
{
return source.Where(value => value > 0);
}
}

First-class function#

So far C# has been demonstrated to have first class functions. C# function can be compared to C# object side by side:

Data (object)Function (method)
TypeObject type: classFunction type: delegate type
ValueObject: class instanceFunction value: delegate instance
AssignmentCan be assigned to variableCan be assigned to variable
StorageCan be stored in data structureCan be stored in data structure
InputCan be function’s parameterCan be higher-order function’s parameter
OutputCan be function’s return valueCan be higher-order function’s return value
NestingCan be nested (e.g. Exception.InnerException)Can be nested (function in function): anonymous function, lambda expression, closure with non-local variable access
EqualityReference equality testableReference equality testable

They can have type and instance:

public static partial class FirstClass
{
public class ObjectType
{
public ObjectType InnerObject { get; set; }
}
public delegate void FunctionType();
public static void ObjectInstance()
{
ObjectType objectValue = new ObjectType();
}
public static void FunctionInstance()
{
FunctionType functionValue1 = FunctionInstance; // Named function.
FunctionType functionValue2 = () => { }; // Anonymous function.
}
}

They can be stored in data structure:

public static partial class FirstClass
{
public static ObjectType objectField = new ObjectType();
public static FunctionType functionField1 = FunctionInstance; // Named function.
public static FunctionType functionField2 = () => { }; // Anonymous function.
}

They can be function parameter and return value:

public static partial class FirstClass
{
public static ObjectType InputOutputObject(ObjectType objectValue) => objectValue;
public static FunctionType InputOutputFunction(FunctionType functionValue) => functionValue;
}

They can be nested:

public static partial class FirstClass
{
public static void NestedObject()
{
ObjectType outerObject = new ObjectType()
{
InnerObject = new ObjectType()
};
}
public static void NestedFunction()
{
object nonLocalVariable = new object();
FunctionType outerFunction = () =>
{
object outerLocalVariable = nonLocalVariable;
FunctionType innerFunction = () =>
{
object innerLocalVariable = nonLocalVariable;
};
};
}
}

They are reference equality testable:

public static partial class FirstClass
{
public static void ObjectEquality()
{
ObjectType objectValue1;
ObjectType objectValue2;
objectValue1 = objectValue2 = new ObjectType();
bool areEqual1 = objectValue1 == objectValue2; // true.
ObjectType objectValue3 = null;
bool areEqual2 = objectValue2 == objectValue3; // false.
}
public static void FunctionEquality()
{
FunctionType functionValue1;
FunctionType functionValue2;
functionValue1 = functionValue2 = () => { };
bool areEqual1 = functionValue1 == functionValue2; // true.
FunctionType functionValue3 = null;
bool areEqual2 = functionValue2 == functionValue3; // false.
}
}

Apparently, C# treats functions as first-class citizen, just like C# objects.

Understanding C# Features (7) Higher-Order Function
https://dixin.github.io/posts/understanding-csharp-features-7-higher-order-function/
Author
Dixin
Published at
2016-01-18
License
CC BY-NC-SA 4.0