Express Yourself: Immutability

Immutability

The easiest way to tame side effects in C# is to enforce immutability within our custom types.

Immutable Objects: an object whose state cannot be modified after it is created

public class DateRange
{
    public DateTime Start { get; set; }
    public DateTime End { get; set; }

    public bool DateIsInRange(DateTime checkDate)
    {
        return Start.CompareTo(checkDate) <= 0 && End.CompareTo(checkDate) >= 0;
    }
}
  • Types are mutable
  • Type can be shared across multiple threads
  • Will cause problems when running in parallel

By building some locking strategy to ensure that one thread does not change the state of the type, we will avoid producing incorrect results on another thread.

Private Setters

One way to enforce immutability is by setting the Start and End property setters to private and add a constructor to set those values.

public class DateRange
{
    public DateTime Start { get; private set; }
    public DateTime End { get; private set; }

    public DateRange(DateTime start, DateTime end){
        if(start.CompareTo(end) >= 0)
            throw new Exception("End must occur after start.")
        Start = start;
        End = end;
    }

    public bool DateIsInRange(DateTime checkDate)    {
        return Start.CompareTo(checkDate) <= 0 && End.CompareTo(checkDate) >= 0;
    }
}

This makes the type immutable from outside the class; however, lets see how we can make them immutable from internal.

public class DateRange
{
    public DateTime Start { get; private set; }
    public DateTime End { get; private set; }

    public DateRange(DateTime start, DateTime end){
        if(start.CompareTo(end) >= 0)
            throw new Exception("End must occur after start.")
        Start = start;
        End = end;
    }

    public void Slide(int days){
        Start = Start.AddDays(days);
        End = End.AddDays(days);
    }

    public bool DateIsInRange(DateTime checkDate)    {
        return Start.CompareTo(checkDate) <= 0 && End.CompareTo(checkDate) >= 0;
    }
}

As you can see in the new function “Slide” we are setting Start and End values to represent new dates.

Read-Only Modifier 

To make the class truly immutable, we must replace the auto-implemented properties with explicit properties backed by read-only fields

public class DateRange
{
    private readonly DateTime _start;
    private readonly DateTime _end;

    public DateTime Start { get { return _start; } }
    public DateTime End { get { return _end; } }

    public DateRange(DateTime start, DateTime end){
        if(start.CompareTo(end) >= 0)
            throw new Exception("End must occur after start.")
        _start = start;
        _end = end;
    }

    public void Slide(int days){
        Start = Start.AddDays(days);
        End = End.AddDays(days);
    }

    public bool DateIsInRange(DateTime checkDate)    {
        return Start.CompareTo(checkDate) <= 0 && End.CompareTo(checkDate) >= 0;
    }
}

The read-only modifier on these field definitions means that we can set the field’s value only as part of the declaration or in the constructor. Setting the value anywhere else will result in a compiler error.

We set the properties in the constructor.

        _start = start;
        _end = end;

Updated the properties with explicit getters that return the backing field values

    public DateTime Start { get { return _start; } }
    public DateTime End { get { return _end; } }

By introducing and updating these properties, our “Slide” method is now broken and must be updated since we were trying to change the property values via the private setter.

public class DateRange
{
    private readonly DateTime _start;
    private readonly DateTime _end;

    public DateTime Start { get { return _start; } }
    public DateTime End { get { return _end; } }

    public DateRange(DateTime start, DateTime end){
        if(start.CompareTo(end) >= 0)
            throw new Exception("End must occur after start.")
        _start = start;
        _end = end;
    }

    public void Slide(int days){
        return new DateRange(Start.AddDays(days), End.AddDays(days));
    }

    public bool DateIsInRange(DateTime checkDate)    {
        return Start.CompareTo(checkDate) <= 0 && End.CompareTo(checkDate) >= 0;
    }
}

As you can see, we are now returning a new value rather than changing the original object’s state.

    public void Slide(int days){
        return new DateRange(Start.AddDays(days), End.AddDays(days));
    }

This makes executing the “Slide” method an expression

Alternative C# 6

    public DateTime Start { get; }
    public DateTime End { get; }

C# 6 introduced getter-only auto-properties which define the backing fields as read-only for us.

public class DateRange
{
    public DateTime Start { get; }
    public DateTime End { get; }

    public DateRange(DateTime start, DateTime end){
        if(start.CompareTo(end) >= 0)
            throw new Exception("End must occur after start.")
        Start = start;
        End = end;
    }

    public void Slide(int days){
        return new DateRange(Start.AddDays(days), End.AddDays(days));
    }

    public bool DateIsInRange(DateTime checkDate)    {
        return Start.CompareTo(checkDate) <= 0 && End.CompareTo(checkDate) >= 0;
    }
}

As you can see, we do not need all those read-only backing fields and explicit properties anymore.

 

<-  What is Functional Programming

What is Functional Programming

OO vs Fp

“No matter what language you work in, programming in a functional style provides benefit. you should do it whenever it is convenient, and you should think hard about the decision when it isn’t convenient.”
– John Carmack

When you apply the basic functional principles to your software, your resulting product will be more predictable, reliable and maintainable.

Clean Code: Chapter03 – Functions

  • Keep functions small
  • Don’t repeat yourself
  • One job
  • Avoid side-effects
  • 3 parameters max

OO makes code understandable by encapsulating moving parts. FP makes code understandable by minimizing moving parts.

— Michael Feathers (@mfeathers) November 3, 2010

Both Object Orientation and Functional Programming try to solve the same problem, but take very different approaches. Object Orientation tries to manage the ever changing state of a system, while Functional Programming is trying to avoid that state altogether.

The main difference between Object Orientation and Functional Programming is how you compose your application.

Defining FP

Functional programming is a paradigm which concentrates on computing results rather than on performing actions.

-Dave Fancher

Central Themes of Functional Programming

1. Tamed Side Effects

Side effect in programming is anything that happens to the state of a system resulting of invoking a function.

Language Purity
Purely Functional Impure
Guarantees (except in certain limited cases) that functions do not have side effects No guarantee about functions and side effects
Functions always behave the same way regardless of the external state of the system
This allows parallel or asynchronous execution
2. Emphasizing Expressions

Everything produces a result

Statements vs Expressions

Statements Expressions
Define actions Produces Results
Executed for their side effects Execute for their results
var posAndNeg;
if(value > 0)
     posAndNeg = 'positive';
else
     posAndNeg = 'negative';
var posAndNeg = 
     value > 0
          ? 'positive'
          : 'negative';
  • Functional Programming is usually shorter.
  • We do not have unassigned variable
  • Fp tend to be more testable
3. Treat Functions as Data

Higher Order Functions

  • Functions which accept other Functions
  • Functions which return a Function

LINQ example

myList
     .Where(x => x % 2 == 0)
     .OrderBy( x => x);

 

Pros Cons
Produces Results More Memory Allocation
Does not alter the original Source
Allows Asynchronous Runs

 

 

Express Yourself: Immutability  ->