Here is an example of some code that is designed to be functional, that is, its designed to enforce immutability and restrict the creation of exceptions - which can change the outcome of functions unpredictably.

There is a lot to be said about this code, including a mysterious Option<T> class from the Language.Ext project but I'll do that next time. For now just look at how it's trying to achieve immutability, mostly around making new copies when its asked to modify itself. Enjoy!

namespace FunctionalProgramming
{
    /// <summary>
    /// This is an immutable object because:
    /// a) Has private setters and that means its state cannot be changed after creation
    /// b) All properties are immutable - either strings or native types or System.Collections.Immutable types
    /// c) Any change that needs to take place must result in a newly create object of this type
    /// </summary>
    public class Person
    {
        public string FirstName { get; }
        public string LastName { get; }

        /// <summary>
        /// Notice this is a private constructor so a Person cannot be created normally...there must be another way in!
        /// It must be created indirectly via .Of() or .New() which then can use the private constructor below
        /// </summary>
        /// <param name="firstName">the persons first name</param>
        /// <param name="lastName">The persons last name</param>
        private Person(string firstName, string lastName)
        {
            if (!IsValid(firstName, lastName))
            {
                throw new ArgumentException("Invalid input");
            }
            FirstName = firstName;
            LastName = lastName;
        }

        /// <summary>
        ///  This pretends to be a constructor by being the only method allowed to call the constructor.
        ///  The actual and real constructor is only called if input is valid to this function 
        ///  As a result it gaurentees no exceptions can ever be thrown during creation of the object through
        ///  this method.
        /// </summary>
        /// <param name="firstName">Persons first name</param>
        /// <param name="lastName">Persons last name</param>
        /// <returns></returns>
        public static Option<Person> Of(string firstName, string lastName) 
            => IsValid(firstName, lastName) 
                ? Option <Person>.Some(new Person(firstName, lastName)) 
                : Option <Person>.None;

        private static bool IsValid(string firstName, string lastName)
            => string.IsNullOrEmpty(firstName) && string.IsNullOrEmpty(lastName);

        // Instance method allows this function to be chained.
        // With Helper to make object creation easier as properties of the object change
        public Person With(string firstName = null, string lastName = null)
        {
            return new Person(firstName ?? this.FirstName, lastName ?? this.LastName);
        }
    }
    // Extension methods allow us to chain non-instance method calls,
    public static class PersonExtensions
    {
        /// <summary>
        /// Functional because 
        /// A) it does not call any non-pure functions or use any other data than the arguments(with are immutable) passed to it.
        /// B) functions should be declared separately from the data they act upon, like it is
        /// C) Creates a new Object 
        /// </summary>
        /// <param name="person"></param>
        /// <param name="firstName"></param>
        /// <returns></returns>
        public static Person Rename(this Person person, string firstName)
        {
            return person.With(firstName: firstName);
        }
    }
}

 The source for this is here: https://github.com/stumathews/FunctionalProgrammingTests/blob/master/FunctionalProgramming/Program.cs


Comments powered by CComment

Twitter