C# Covariance and what has to do with Functional C#

Dimitris Papadimitriou
3 min readJun 25, 2022

No covariance is not a hard concept.Its is actually very easy to grasp.

Source : https://gist.github.com/dimitris-papadimitriou-chr/578f76c2d4b8d18f6f7fc8e69dcf0153

No covariance is not a hard concept.Its is actually very easy to grasp.

What is covariance in C# and what has to do with functional C#.

The Problem

Assume that you have this simple

   public interface IWithSuccess
{
public bool IsSuccesfull { get; }
}
public class SomeResult : IWithSuccess
{
public bool IsSuccesfull => true;
}

Amazingly you cannot write the following code even if you might Expected to:

Func<Task<SomeResult>> GetSomethingLazyAsync() =>...

//Error CS0029 Cannot implicitly convert types !!!!!!!!!
Func<Task<IWithSuccess>> lazyResult= GetSomethingLazyAsync();

Assign something that might look like more specific to something that seems more general in nature.

Assign a Func<Task<SomeResult>> to a Func<Task<IWithSuccess>> as you can assign a SomeResult to an IWithSuccess

if you go to the Func<_> declaration you might see the following:

public delegate TResult Func<out TResult>();

which you should keep in mind because this means that an assignment of

Func<SomeResult> to a Func<IWithSuccess> is perfectly fine and you can use this. But the Task spoils all the Fun(c) here.

My Favorite Solution

Use the adapter pattern in a minimal form and Extension methods to Chain conversion.

1) First generate the following

public interface IFuncTask<out T>
{
T GetResult();
}
public class FuncTaskAdapter<T> : IFuncTask<T>
{
public FuncTaskAdapter(Func<Task<T>> funcTask) =>
this.funcTask = funcTask;
public T GetResult() => funcTask().Result;

}

2)Now we can use Extension methods to make a conversion under the hood

public static partial class FunctionalExtensions
{
public static IFuncTask<T> ToWithResult<T>(this Func<Task<T>> @this) => new FuncTaskAdapter<T>(@this);

}

3) now we can write :

IFuncTask<IWithSuccess> t = GetSomethingLazyAsync()
.ToWithResult();

covariance works now !!!

what i did is that i made the decision to sacrifice the knowledge that there is a Task there, with the minimal ability to get a Result if i ever need it.

public T GetResult() => funcTask().Result;

Obviously this conversion is usefully only at the late stages of computation where we are reaching a conclusion on the outcome and we no longer need any Task related ‘capabilities’ . For example we can add the following extension method on top of IFuncTask<>

public static T GetOrThrowIfFailed<T>(this FuncTask<T> @this, string message) where T : IWithResult
{
var value = @this(); // this might also throw exception from Task.
return value?.IsSuccesfull ?? false ? value :
throw new Exception(message);
}

and use this like this :

//ok this is covariant on T
FuncTask<IWithResult> lazyResult = GetSomethingLazyAsync().ToFuncTask();

SomeResult result = GetSomethingLazyAsync().ToFuncTask().GetOrThrowIfFailed("failed to get");

of course the Great advantage is what i call ‘Syntax extensibility’ and ‘Syntax coupling’. When i say syntax extensibility is the ability of functional syntax to be decorated with minimal modification in code. Compared to classical syntax, which is a mess and the cross cutting concerns or different intentional concerns are coupled with the computation.

Syntax Extension

For example we could create a simple extension method called GetOrThrow build on top of GetOrThrowIfNull, aka decorates GetOrThrowIfNull (aka Functional Decorator pattern) that simply adds an additional try/catch for the Exception or Func failures

public static T GetOrThrow<T>(this IFuncTask<T> @this, string message)
{
try
{
return @this.GetOrThrowIfNull(message);
}
catch (Exception e) //Please Dont hide Exceptions
{
throw new Exception(message);
}

}

in the functional syntax this would be applied by simply

SomeResult result = GetSomethingLazyAsync()
.ToWithResult()
.GetOrThrow("failed to get");

whereas in classical syntax this would force us to do the following

         SomeResult result;
try
{
var lazyTask = GetSomethingLazyAsync();
result = await lazyTask();
if (result is null)
throw new Exception("failed to get Anything");
}
catch (Exception e) //Please Dont hide Exceptions
{
throw new Exception("failed to get Anything");
}

Source : Extended Version

do you want to see more thoughts on this. check out this : “Delegates as Adapters C# : More covariance

How do i come up with those coding insight? By mastering the essentials of Functional C# https://leanpub.com/functional-programming-in-cSharp-with-categories

--

--