Knowledge-base
  • Home
  • Samman Technical Coaching
  • Software craftsmanship
    • Practices
      • Pair Programming
      • Code Review
      • Co-designs
      • Design sessions
      • Interview Domain Experts
      • Dev ethics
    • The Software Craftsman
    • Egoless Crafting
    • Technical debt workshop
    • Functional Programming made easy in C# with Language-ext
    • F# for OO programmers
    • Domain Modeling Made Functional
    • Testing
      • Clean Tests
      • Improve the design and testing of your micro-services through CDC Tests
        • CDC testing made simple with Pact
        • Pact broker : the missing piece of your Consumer-Driven Contract approach
      • Improve your test quality with Mutation testing
      • How to name our Unit Tests
      • How to write better assertions
    • Katas
      • TDD
        • Stack kata
        • Fizzbuzz
        • Outside-in TDD (London Style)
      • Improve your software quality with Property-Based Testing
        • A journey to Property-Based Testing
      • Clean Code
      • Clean Architecture
      • Write S.O.L.I.D code
      • Mocking
      • Gilded Rose (Approval Testing)
      • Mikado method
        • Mikado kata
      • Pure functions
      • Theatrical players refactoring Kata
        • Let's refactor (OOP style)
        • Let's refactor (FP style)
      • Functional Programming made easy in Java & C#
      • Refactoring journey
      • Refactoring du Bouchonnois
        • 1) Se faire une idée du code
        • 2) "Treat warnings as errors"
        • 3) Let's kill some mutants
        • 4) Améliorer la lisibilité des tests
        • 5) "Approve Everything"
        • 6) Définir des propriétés
        • 7) Tests d'architecture
        • 8) Use Cases
        • 9) Tell Don't Ask
        • 10) "Avoid Primitives" - Commands
        • 11) "Avoid Exceptions"
        • 12) "Event Sourcing"
    • Software Design X-Rays
      • Workshop
    • The Programmer's Brain
      • How to read code better
  • Software Architecture
    • Fundamentals of Software Architecture
    • Aligning Product & Software Design
    • DDD re-distilled
    • Test your architecture with Archunit
    • NoSQL
  • Agile coaching
    • How to run a Community of Practices (COP)
    • The developers — the forgotten of agility
      • The secrets to re-on-board the devs in agility
    • Coaching toolbox
      • Echelle
      • Learning expedition
    • How to improve Team Decision making ?
      • Decision Making Principles and Practices
    • Learning 3.0
    • Retrospectives
      • Back to the Future
      • Mission Impossible
      • Movie themes
      • Rétro dont vous êtes le héros
      • Sad/Mad/Glad
      • Speed boat
      • Star wars theme
      • Story cubes
    • Technical Agile Coaching with the Samman Method
    • Xanpan - a team centric agile method story
    • XTREM WATCH — Découvrez la puissance de la veille collective
    • Become a better speaker through peer feedback
    • Project-to-Product Principles
  • Leadership
    • Bref. J'ai pris une tarte dans la gueule (et ça fait extrêmement de bien)
    • Forward Summit 2020
    • Learn leadership from the Navy SEALs
    • Learn to lead and help your team(s) to be successful
    • Towards a learning organization and beyond
    • Leadership is language
  • Serious games
    • My serious games
    • Libérez vos entretiens d’embauche avec la gamification
    • How to create a game
    • How to debrief a game ?
    • Lego Serious Play (LSP)
      • LSP in your job interviews
  • Xtrem Reading
    • Cultivate Team Learning with Xtrem Reading
    • My Book Infographics
    • How to make book infographics
    • En route vers l’apprenance avec Xtrem Reading
    • Resources
      • Book notes
        • Agile People: A Radical Approach for HR & Managers
        • Agile testing : A Practical Guide for Testers and Agile Teams
        • Boite à outils de l'intelligence émotionnelle
        • Building a better business using Lego Serious Play method
        • Building evolutionary architectures
        • Code that fits in your head
        • Culture Agile
        • Culture is everything
        • Domain-Driven Design: The First 15 Years
        • Dynamic Reteaming - The Art and Wisdom of Changing Teams
        • How to avoid a Climate Disaster
        • La liberté du commandement
        • Réaliser ses rêves, ça s'apprend
        • Refactoring at Scale
        • Succeeding with OKRs in Agile
        • Team Topologies
        • The Good Life
        • Tu fais quoi dans la vie
        • Who Does What By How Much?
  • My Activity
    • Retour sur mon année 2020
Powered by GitBook
On this page
  • OK but why don’t we use a FP language instead of C# ?
  • Let’s demystify Functional Programming (FP)
  • Immutability
  • Pure Functions
  • Higher order function
  • What is Language-ext ?
  • Language-ext vs LinQ
  • Easy immutable record types
  • No more out parameters
  • Option
  • Lists are functors
  • Function composition
  • Bind
  • Try
  • Memoization
  • Partial application
  • Either
  • Fold vs Reduce (Aggregate in LinQ)
  • Real life example
  • Conclusion
  • Resources

Was this helpful?

  1. Software craftsmanship

Functional Programming made easy in C# with Language-ext

Read this article if you want to demystify Functional Programming and understand why and how to start using FP paradigms in C#.

PreviousTechnical debt workshopNextF# for OO programmers

Last updated 4 years ago

Was this helpful?

In the title I have written FP and C# but the question you probably wonder is :

What the hell should we want to use FP paradigms in an OO language like C# ?

Here are some arguments to answer this question (from my POV) :

  • Write less code and more meaningful one : improved code clarity

  • Avoid side effects by using immutability and pure functions : Easier concurrent programming

  • Easier testing : it’s really easy to test functions

  • Easier debugging

  • Funnier to write

OK but why don’t we use a FP language instead of C# ?

In companies it’s really hard to change the habits. We don’t all work in the Sillicon Valley and in my reality the latest versions in the production environments are : Java 8, .NET Framework 4, NodeWhat ?, …

In my world organizations are not yet ready to invest in pure FP languages like F#, Kotlin, Clojure or whatever. They are stuck in legacy code…

It’s a pattern that could be really useful to every developers on earth I think.

  • Functional core (declarative) composed of pure functions (in / out) and easy to test without any mocks.

  • Imperative shell or reactive container the service logic that you can test with integration tests

Now I have proved the interest of FP in OO language let’s go for a quick lesson.

Let’s demystify Functional Programming (FP)

Basically FP is all about functions and immutability :

  • Pure functions

  • Lambda functions (anonymous)

  • High order functions

  • Composition

  • Closures

  • Currying & partial application

  • Recursion

If you have already looked at it, you have probably read other words like functors, monads and monoïds that can be very scary but in reality concepts are not.

Let’s start by explaining 3 concepts :

Immutability

We never want to mutate an object in FP we want to avoid side effects so we prefer creating a new one. If we have mutable objects it could be possible for another function to mutate the object we were working on concurrently.

Immutability ensures a function remains pure, it makes concurrency much more easy to handle and makes our dev life easier.

Pure Functions

Combined with immutable data types mean you can be sure the same inputs will give the same outputs.

Higher order function

A function that does at least one of the following:

  • Takes one or more functions as arguments

  • Returns a function as its result

A higher order function that takes 2 functions as arguments

Before demonstrating code I highly recommend you to read this great article about FP concepts (I won’t do better for sure) :

Now you know the basics behind FP we can start deep diving into Language-ext.

What is Language-ext ?

His desire here is to make programming in C# much more reliable and to make the engineer’s inertia flow in the direction of declarative and functional code rather than imperative.

Language-ext vs LinQ

Yes FP paradigms in C# exist since the introduction of LinQ. Here is a mapping between some language-ext functionalities and their equivalence in LinQ :

Easy immutable record types

Implementing immutable data structures is a nightmare in OO languages (Equals, GetHashCode, IEquatable<A>, IComparer<A>, implementing operators: ==, !=, <, <=, >, >=).

That’s why there is a Record class in language-ext :

public class User
{
    public readonly Guid Id;
    public readonly string Name;
    public readonly int Age;

    public User(Guid id, string name, int age)
    {
        Id = id;
        Name = name;
        Age = age;
    }
}

public class UserRecord : Record<UserRecord>
{
    public readonly Guid Id;
    public readonly string Name;
    public readonly int Age;

    public UserRecord(Guid id, string name, int age)
    {
        Id = id;
        Name = name;
        Age = age;
    }
}

[Fact]
public void record_types()
{
    var spongeGuid = Guid.NewGuid();

    var spongeBob = new User(spongeGuid, "Spongebob", 40);
    var spongeBob2 = new User(spongeGuid, "Spongebob", 40);

    Assert.False(spongeBob.Equals(spongeBob2));

    // Use immutable records available in Language-ext
    var spongeBobRecord = new UserRecord(spongeGuid, "Spongebob", 40);
    var spongeBobRecord2 = new UserRecord(spongeGuid, "Spongebob", 40);

    Assert.True(spongeBobRecord.Equals(spongeBobRecord2));
}

No more out parameters

Yes in C# we have out parameters on TryParse for example now it’s finished :

Option

Many functional languages disallow null values, as null-references can introduce hard to find bugs. Option is a type safe alternative to null values. (it also exists in F#).

Avoid nulls by using an Option

An Option<T> can be in one of two states : some => the presence of a value none => lack of a value

Option<int> aValue = 2;
aValue.Map(x => x + 3); // Some(5)

Option<int> none = None;
none.Map(x => x + 3); // None

//Left -> Some, Right -> None
aValue.Match(x => x + 3, () => 0); // 5
none.Match(x => x + 3, () => 0); // 0

// Returns the Some case 'as is' -> 2 and 1 in the None case
int value = aValue.IfNone(1);
int noneValue = none.IfNone(42); // 42

Match : match down to primitive type

Map : We can match down to a primitive type, or can stay in the elevated types and do logic using map.

  • Lambda inside map won’t be invoked if Option is in None state

  • Option is a replacement for if statements ie if obj == null

  • Working in elevated context to do logic

Lists are functors

We can map them :

new int[] { 2, 4, 6 }.Map(x => x + 3); // 5,7,9
new List<int> { 2, 4, 6 }.Map(x => x + 3); // 5,7,9
//Prefer use List (Immutable list)
List(2, 4, 6).Map(x => x + 3); // 5,7,9

Function composition

What happens when you apply a function to another function? When you use map on a function, you’re just doing function composition :

static Func<int, int> Add2 = x => x + 2;
static Func<int, int> Add3 = x => x + 3;

static int Add5(int x) => Add2.Compose(Add3)(x);

Bind

Monads apply a function that returns a wrapped value to a wrapped value. Monads have a function “bind” to do this.

Suppose half is a function that only works on even numbers.

What if we feed it a wrapped value? This is where bind comes in!

static Option<double> Half(double x)
    => x % 2 == 0 ? x / 2 : Option<double>.None;

[Fact]
public void bind_monad()
{
    Option<double>.Some(3).Bind(x => Half(x));// None
    Option<double>.Some(4).Bind(x => Half(x));// Some(2)
}

[Fact]
public void chain_bind_monad()
{
    Option<double>.Some(20)
        .Bind(x => Half(x))// Some(10)
        .Bind(x => Half(x))// Some(5)
        .Bind(x => Half(x));// None
}

Try

Exception handling made easier the use of try. No more needs of ugly try/catch that pollutes the flow of your code you can describe your pipeline in a really readable way.

public void file_monad_example()
{
    GetLine()
        .Bind(ReadFile)
        .Bind(PrintStrln)
        .Match(success => Console.WriteLine("SUCCESS"),
                failure => Console.WriteLine("FAILURE"));
}

static Try<string> GetLine()
{
    Console.Write("File:");
    return Try(() => Console.ReadLine());
}

static Try<string> ReadFile(string filePath) => Try(() => File.ReadAllText(filePath));

static Try<bool> PrintStrln(string line)
{
    Console.WriteLine(line);
    return Try(true);
}

Here if something fails, you have the exception in the failure match part. The better part is that Try has a brother called TryAsync that is demonstrated in the real life example.

Memoization

Memoization is some kind of caching, if you memoize a function, it will be only executed once for a specific input.

static Func<string, string> GenerateGuidForUser = user => user + ":" + Guid.NewGuid();
static Func<string, string> GenerateGuidForUserMemoized = memo(GenerateGuidForUser);

[Fact]
public void memoization_example()
{
    GenerateGuidForUserMemoized("spongebob");// spongebob:e431b439-3397-4016-8d2e-e4629e51bf62
    GenerateGuidForUserMemoized("buzz");// buzz:50c4ee49-7d74-472c-acc8-fd0f593fccfe
    GenerateGuidForUserMemoized("spongebob");// spongebob:e431b439-3397-4016-8d2e-e4629e51bf62
}

Partial application

Partial application allows you to create new function from an existing one by setting some arguments.

static Func<int, int, int> Multiply = (a, b) => a * b;
static Func<int, int> TwoTimes = par(Multiply, 2);

[Fact]
public void partial_app_example()
{
    Multiply(3, 4); // 12
    TwoTimes(9); // 18
}

Either

Either represents a value of two types, it is either a left or a right by convention left is the failure case, and right the success case.

public static Either<Exception, string> GetHtml(string url)
{
    var httpClient = new HttpClient(new HttpClientHandler());
    try
    {
        var httpResponseMessage = httpClient.GetAsync(url).Result;
        return httpResponseMessage.Content.ReadAsStringAsync().Result;
    }
    catch (Exception ex) { return ex; }
}

[Fact]
public void either_example()
{

    GetHtml("unknown url"); // Left InvalidOperationException
    GetHtml("https://www.google.com"); // Right <!doctype html...

    var result = GetHtml("https://www.google.com");

    result.Match(
            Left: ex => Console.WriteLine("an exception occured" + ex),
            Right: r => Console.WriteLine(r)
        );
}

Fold vs Reduce (Aggregate in LinQ)

  • Fold takes an explicit initial value for the accumulator. The accumulator and result type can differ as the accumulator is provided separately.

  • Reduce uses the first element of the input list as the initial accumulator value (just like the Aggregate function). The accumulator and therefore result type must match the list element type.

[Fact]
public void fold_vs_reduce()
{
    //fold takes an explicit initial value for the accumulator
    //Can choose the result type
    var foldResult = List(1, 2, 3, 4, 5)
        .Map(x => x * 10)
        .Fold(0m, (x, s) => s + x); // 150m

    //reduce uses the first element of the input list as the initial accumulator value
    //Result type will be the one of the list
    var reduceResult = List(1, 2, 3, 4, 5)
        .Map(x => x * 10)
        .Reduce((x, s) => s + x); // 150
}

Real life example

This example demonstrates the kind of usage you could have of language-ext in application services : chaining operations / pipelining, improve error handling, no more redundant checks, …

using System;
using System.Threading.Tasks;
using LanguageExt;
using static LanguageExt.Prelude;

namespace language_ext.kata.Account
{
    public class AccountService
    {
        private readonly UserService userService;
        private readonly TwitterService twitterService;
        private readonly IBusinessLogger businessLogger;

        public AccountService(UserService userService, TwitterService twitterService, IBusinessLogger businessLogger)
        {
            this.userService = userService;
            this.twitterService = twitterService;
            this.businessLogger = businessLogger;
        }

        private TryAsync<RegistrationContext> CreateContext(Guid userId) =>
            TryAsync(() => userService.FindById(userId)).Map(user => new RegistrationContext(user));

        private TryAsync<RegistrationContext> RegisterOnTwitter(RegistrationContext context) =>
            TryAsync(() => twitterService.Register(context.Email, context.Name)).Map(context.SetAccount);

        private TryAsync<RegistrationContext> AuthenticateOnTwitter(RegistrationContext context) =>
            TryAsync(() => twitterService.Authenticate(context.Email, context.Password)).Map(context.SetToken);

        private TryAsync<RegistrationContext> Tweet(RegistrationContext context) =>
            TryAsync(() => twitterService.Tweet(context.Token, "Hello I am " + context.Name)).Map(context.SetTweetUrl);

        private TryAsync<RegistrationContext> UpdateUser(RegistrationContext context) =>
            TryAsync(async () =>
            {
                await userService.UpdateTwitterAccountId(context.Id, context.AccountId);
                return context;
            });

        public async Task<Option<string>> Register(Guid id)
        {
            return await CreateContext(id)
                    .Bind(RegisterOnTwitter)
                    .Bind(AuthenticateOnTwitter)
                    .Bind(Tweet)
                    .Bind(UpdateUser)
                    .Do(context => businessLogger.LogSuccessRegister(context.Id))
                    .Map(context => context.Url)
                    .IfFail(failure =>
                    {
                        businessLogger.LogFailureRegister(id, failure);
                        return (string)null;
                    });
        }
    }
}

Conclusion

Start using language-ext in your projects is a really good idea. This lib can make your life much more easier.

You can see it at your first step to go into the FP world, before one day be able to use a language like Clojure or F#.

Resources

If you want to go further :

To go further on this topic I invite you to watch this video on Functional Core, Imperative Shell :

“In computer science, functional programming is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data.” —

A pure function don’t refer to any global state. The same inputs will always get the same output.

According to the creator of the lib : It’s a library that uses and abuses the features of C# to provide a functional-programming ‘base class library’ that, if you squint, can look like extensions to the language itself.

It’s basically “one lib to rule them all” :

All the source code is available in my github repository : .

FP in pictures :

Gitter on language-ext :

Doc and examples :

What’s new in C# 8 :

“functional core, imperative shell” video :

Domain modeling made functional book from Scott Wlaschin :

https://discventionstech.wordpress.com/2017/06/30/functional-core-and-imperative-shell/
wikipedia
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html#just-what-is-a-functor,-really?
Paul Louth
https://github.com/louthy/language-ext
https://github.com/ythirion/fp-in-csharp-sandbox
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html#just-what-is-a-functor,-really?
https://gitter.im/louthy/language-ext
https://github.com/louthy/language-ext/issues
https://medium.com/swlh/how-c-8-helps-software-quality-cfa81a18907f
https://discventionstech.wordpress.com/2017/06/30/functional-core-and-imperative-shell/
https://www.amazon.com/Domain-Modeling-Made-Functional-Domain-Driven/dp/1680502549/ref=sr_1_1?crid=FXE4W7BCGETO&keywords=domain+modeling+f%23&qid=1576686914&sprefix=design+thin%2Caps%2C330&sr=8-1
Image for post