Single return versus multiple return

Imagine the maitre d’ at a restaurant. When a diner enters the restaurant the maitre d’ has to perform a number of checks to determine whether the diner is allowed a table. When we take this real world scenario and convert it into code, we end up writing a validation function.

If the rules are:

  • Check the diner is old enough
  • Check the booking exists
  • Check the booking has not expired
  • Check there is a table available

Then we can write the code as follows:

public bool ValidateDiner(Person person, DateTime dateNow)
{
    bool valid = false;

    if (person.Age >= _Restaurant.MinimumBookingAge)
    {
        Booking booking = GetBooking(person.Id);
        if (booking != null)
        {
            TimeSpan timeUntilBooking = (booking.Date - dateNow).Duration();
            if (!(timeUntilBooking.TotalMinutes < _Restaurant.MaximumWaitingMinutes))
            {
                if (_Restaurant.HasTableAvailable())
                {
                    valid = true;
                }
            }
        }
    }

    return valid;
}

This code uses the principle of returning once. Although some programmers are productive results adhering to this rule, I would rewrite this function to have multiple return statements, to fail early and fail fast.

Here is a rewritten validation method with multiple return statements:

public bool ValidateDiner_EarlyExit(Person person, DateTime dateNow)
{
    if (person.Age < _Restaurant.MinimumBookingAge)
    {
        return false;
    }
    
    Booking booking = _GetBooking(person.Id);
    if (booking == null)
    {
        return false;
    }
    
    TimeSpan timeUntilBooking = (booking.Date - dateNow).Duration();
    if (timeUntilBooking.TotalMinutes < _Restaurant.MaximumWaitingMinutes)
    {
        return false;
    }
    
    if (!_Restaurant.HasTableAvailable())
    {
        return false;
    }
    
    return true;
}

Code Complete provides the following guidance on return statements:

  • Minimise the number of returns in each routine
  • Use a return when it enhances readability

Returning early does enhance readability in this example. The aim of the method is to cause input to fail validation and validation failure is the common case.

Another structural possibility is to decouple the validator from the validation rules with this schema:

private readonly List<Func<Person, bool>> m_listValidationRules = new List<Func<Person, bool>>();

public void AddRules()
{
    m_listValidationRules.Add(person => person.Age >= _Restaurant.MinimumBookingAge);
    m_listValidationRules.Add(person => _GetBooking(person.Id) != null);
    m_listValidationRules.Add(person =>
    {
        Booking booking = _GetBooking(person.Id);
        if (booking == null)
        {
            return false;
        }
        
        TimeSpan timeUntilBooking = (booking.Date - DateTime.Now).Duration();
        return timeUntilBooking.TotalMinutes >= _Restaurant.MaximumWaitingMinutes;
    });
    m_listValidationRules.Add(person => _Restaurant.HasTableAvailable());
}

public bool ValidateDiner_RuleList(Person person, DateTime dateNow)
{
    return m_listValidationRules.TrueForAll(validate => validate(person));
}

This can be useful when the rules are optional and/or require additional resources that the validator should not know about.


See also