DIVEX

Join operators

One thing DIVEX is about is delaying the specification of parameter values. This might result in a functions that have similar parameters. Consider the following example:

DelFunc.DF1 postContentToWebService =
    (Document document, HttpClient httpClient, Uri uri, Action<string> log) =>
{
    log("Posting");

    httpClient.PostAsync(
        uri,
        new StringContent(document.Content))
        .Result.EnsureSuccessStatusCode();
};

DelFunc.DF2 readAndProcess =
    (string folderPath, Action<Document> process, Action<string> log) =>
{
    log("Processing folder");

    foreach (var filePath in Directory.GetFiles(folderPath))
    {
        var document = new Document(File.ReadAllText(filePath), Path.GetFileName(filePath));
    }
};

var process = readAndProcess
    .Inject(process: postContentToWebService);

var process2 = process.JoinAllInputs();

process2.Invoke(
    folderPath: @"C:\Documents",
    httpClient: new HttpClient(),
    uri: new Uri("https://local.lab/Document"),
    log: x => Console.WriteLine(x));
DelFunc.DF1 and DelFunc.DF2 are Delegate Functions. Delegate Functions is a way to support treating lambdas as functions.

The process function in the example above has the following signature:

There are two parameters named log. And DIVEX is displaying them with a red background to indicate that there are two parameters with the same name. These parameters were bubbled up from readAndProcess and postContentToWebService. These parameters are used in these functions to log messages. In this example, we are interested to log these messages to the same destination. The JoinAllInputs operator finds parameters in the function that have the same name and “joins” them together. In this example, the process2 function has only a single parameter called log. When we invoke process2 in the example above, we provide a single value for log. This value will be used for the two parameters in the process function.

The JoinAllInputs operator works also when we have multiple duplicate parameter groups. For example, if there is a function with two log parameters and three getTime parameters, it will join the two log parameters into a single log parameter, and the three getTime parameters into a single getTime parameter.

The JoinByName operator can be used to join parameters with a specific name together. The following usage of JoinByName can be used as an alternative to the usage of JoinAllInputs in the previous example:

var process2 = process.JoinByName(log: 0);

This usage of JoinByName will join all parameters named log. The zero here has no meaning. It exists to satisfy the C# language.

JoinByType can be used to join parameters that have the same type regardless of the names. Consider this example:

using DIVEX.Core;
using System;
using System.IO;
using System.Net.Http;
using static DIVEX.Core.DivexUtils;

namespace DivexNet5
{
    [DivexCompose]
    public static partial class Program
    {
        public record Document(string Content, string Name);

        public interface ILogger
        {
            void Log(string message);
        }

        public class ConsoleLogger : ILogger
        {
            public void Log(string message)
            {
                Console.WriteLine(message);
            }
        }

        static void Main(string[] args)
        {

            DelFunc.DF1 postContentToWebService =
                (Document document, HttpClient httpClient, Uri uri, ILogger logger1) =>
            {
                logger1.Log("Posting");

                httpClient.PostAsync(
                    uri,
                    new StringContent(document.Content))
                    .Result.EnsureSuccessStatusCode();
            };

            DelFunc.DF2 readAndProcess =
                (string folderPath, Action<Document> process, ILogger logger2) =>
            {
                logger2.Log("Processing folder");

                foreach (var filePath in Directory.GetFiles(folderPath))
                {
                    var document = new Document(File.ReadAllText(filePath), Path.GetFileName(filePath));
                }
            };

            var process = readAndProcess
                .Inject(process: postContentToWebService);

            var process2 = process.JoinByType(logger: OfType<ILogger>());

            process2.Invoke(
                folderPath: @"C:\Documents",
                httpClient: new HttpClient(),
                uri: new Uri("https://local.lab/Document"),
                logger: new ConsoleLogger());
        }
    }
}

In this example, the ILogger parameters are named logger1 and logger2. And these parameters are joined using JoinByType. Since JoinByType allows for joining parameters with different names, we just specify a new parameter name. In the example above, “logger” was used. The OfType method is used to select the type of parameters to join. This is a static method defined in the DIVEX.Core.DivexUtils class. In the above example, I am using the using static directive feature of C# to open this class so that I can use the OfType method directly.