We had a discussion about how validation firstly needs to be done and secondly how horrible it looks if its done multiple times throughout the code. It was briefly mentioned how this can be achieved using the C# type system to do on parameter. This idea in my mind wasn't appreciated and the conversation moved on without exposition on how this can be done. C++ Tends to take this approach a lot and its an approach that favours abstraction to achieve simplicity.

The idea is that if you have a function prototype like this:

int SetName( string firstName, string lastName )

Now this is a contrived example. Which apart from aall other other deficiencies in this line of code is intended by the programmer to mean subtract a from b. Another thing the programmer intends is that this function be correct when its precondition is that b > a.  As I said many deficiencies in this prototype hide intention, pre-conditions and other aspects that the function assumes or requires. This isn't about these kinds problems. I'd like to talk about how ugly the code around it looks:

Base case scenario this code is used like this:

// Is first Name or Last name empty dunno, no indication that it is or should be checked
var result = SetName(formFirstName, formLastName)

Somewhat better but now you can proliferate checking code all over the code:

// precondition check
if(!formFirstName.IsNullOrEmpty())  // basic check
    var result = SetName(formFirstName, formLastName)

But the question arises, "Where should the pre-condition checks occur? In the function or before it". I'd argue that it should be done before but I don't like seeing conditions like the above in the code. You can make the input into the function (a or b ) validate itself before its used in the function by making a new type which cannot be constructed when the a or b is invalid:

int SetName(Person person)

And so in the construction of Person you do your validation and this also as a side effect does the post-condition validation for the function.

 

But what if your constructor throw an exception during construction - that's bad and so we wont use one! How do we get around that? Easy. Smart constructors. This highlights 3 key aspects:

  1. You can force validation of function inputs by using new a new type to validate construction of that type.
  2. You can avoid exception which might have occurred during validation when constructing this new type.
  3. (Bonus) Can also enforce immutability of the input so that functions can be more pure (the input cannot be changed in-place).
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);

    }
    
}

Something like that anyway ;-)

 


Comments powered by CComment

Twitter