Debug-Only Code Without Duplication

thejman

New member
Joined
Jan 25, 2020
Messages
3
Programming Experience
5-10
I'm trying to write something similar to the existing Debug class that allows clients to explicitly verify pre- and post-conditions of their methods. For example, to check a precondition that the input variable to a method is not equal to 0, one would use Expects.IsGreaterThan(input, 0), and that code would evaluate in both debug and release builds to throw an exception if input <= 0. If, however, the client only wanted to have the check in debug builds as a defensive programming tactic but didn't want the overhead of evaluating the condition in release builds (e.g. the input is generated internally and not from user data, so passing a bad value is a bug rather than an exceptional circumstance), then the client would use Expects.Debug.IsGreaterThan(input, 0). Note that the exact syntax here is not set in stone, though I would like to be able to have both `Expects` and `Ensures` (for pre- and post-conditions, respectively) plus debug versions of both.

My issue is figuring out how to do this without having massive code duplication. Every approach that I can think of either requires two separate classes with the exact same code (e.g. using the Conditional("Debug") attribute on the Debug version) or doesn't actually elide the invocation (e.g. using some kind of Boolean policy class and checking that first in the evaluation function). I've considered using a code generator of some sort so that the code is duplicated only as a result but not at the point of authorship, but I'd rather not have to write an entire tool/template for this; there are potentially dozens of functions that I want to include in these utility classes, and describing each in a higher-level language for some generator to ingress would be fairly tedious.

So I'm wondering if anyone has any ideas on how I can do this. Hopefully this problem statement made sense; I can follow up with additional details if need be. Thanks!
 
E.g.
C#:
public static class Expects
{
    public static class Debug
    {
        [Conditional("DEBUG")]
        public static void IsGreaterThan(int actual, int minimum)
        {
            Expects.IsGreaterThan(actual, minimum);
        }
    }

    public static void IsGreaterThan(int actual, int minimum)
    {
        if (!(actual > minimum))
        {
            throw new Exception($"Actual value '{actual}' is not greater than minimum value '{minimum}'.");
        }
    }
}
Yes, you do need to duplicate method signatures, but you don't need to duplicate method bodies. Every method body in the inner class would be a single line that calls the corresponding method in the outer class. As you wrote each method in the outer class, you could copy it to the inner class, replace the body and then add/copy the attribute.
 
Last edited:
Mmk, that's what I was afraid of. I was hoping to come up with a way to avoid duplicating the method signatures, but (unlike with C++) I guess that's not really a possibility here. Thanks though!
 
Your idea of having Expects and Ensures means that you would have to duplicate that entire code and change the Expects class name to Ensures, so you would end up duplicating code anyway. Personally, I wouldn't be separating the two when they do exactly the same thing, unless you want a different set of error messages. That said, if you do want to go that way, you could put all the actual functionality into a single class and then call it from the other four classes, e.g.
C#:
internal static class Assert
{
    public static void IsGreaterThan(int actual, int minimum, string errorMessage)
    {
        if (!(actual > minimum))
        {
            throw new Exception(errorMessage);
        }
    }
}

public static class Expects
{
    public static class Debug
    {
        [Conditional("DEBUG")]
        public static void IsGreaterThan(int actual, int minimum)
        {
            Expects.IsGreaterThan(actual, minimum);
        }
    }

    public static void IsGreaterThan(int actual, int minimum)
    {
        Assert.IsGreaterThan(actual, minimum, $"Actual value '{actual}' is not greater than minimum value '{minimum}'.");
    }
}

public static class Ensures
{
    public static class Debug
    {
        [Conditional("DEBUG")]
        public static void IsGreaterThan(int actual, int minimum)
        {
            Ensures.IsGreaterThan(actual, minimum);
        }
    }

    public static void IsGreaterThan(int actual, int minimum)
    {
        Assert.IsGreaterThan(actual, minimum, $"Actual value '{actual}' is not greater than minimum value '{minimum}'.");
    }
}
 
The plan was something along the lines of this, where the named classes are just specific instantiations of the generic class providing a different exception type. Ultimately, the purpose of separating Expects from Ensures is:
  • When reading code that uses them, it's clear what the author's intention is. True, where it appears in the method would generally be sufficient, but I prefer giving things meaningful names where appropriate.
  • It more closely resembles conventional design-by-contract paradigms.
I was thinking something along the line of

C#:
public sealed class PreConditionFailedException : Exception {
    // constructors omitted for brevity
}

public sealed class PostConditionFailedException : Exception {
    // constructors omitted for brevity
}

public class Verify<E> where E : Exception {
    internal Verify() {}
    
    public static void IsGreaterThan(int lhs, int rhs) {
        if (!(lhs < rhs)) {
            throw System.Activator.CreateInstance(typeof(E)) as E;
        }
    }
    
    // other checks omitted for brevity
}

public sealed class Expects : Verify<PreConditionFailedException> {
    private Expects() : base() {}
}

public sealed class Ensures : Verify<PostConditionFailedException> {
    private Ensurs() : base() {}
}

In this way, I don't have to duplicate anything, because the derived classes inherit the static methods from the base class, but nothing can actually be instantiated; all three classes are effectively static classes. Furthermore, only classes in my library can actually inherit from the core implementation class because of the internal constructor; this turns that base into an implementation detail, which is really what I want it to be.

For reference, I'm far more proficient in C++ than in C# (given that my schooling and day job were/are rooted in C++), so I'm trying to achieve something that would be equivalent to
C++:
class PreConditionFailedException final : public std::exception {
    // constructors omitted for brevity
};

class PostConditionFailedException final : public std::exception {
    // constructor omitted for brevity
};

template <typename T, bool THROW_ON_FAIL>
class Verify {
public:
    #ifdef DEBUG
    using Debug = Verify<T, true>;
    #else
    using Debug = Verify<T, false>;
    #endif

    static void IsGreaterThan(const int lhs, const int rhs) noexcept {
        if constexpr(THROW_ON_FAIL) {
            if (!(ls < rhs)) {
                throw T{};
            }
        }
    }
    
    // other checks omitted for brevity

protected:
    Verify() = default;
};

using Expects = Verify<PreConditionFailedException, true>;
using Ensures = Verify<PostConditionFailedException, true>;

Where (for those unfamiliar with C++) the if constexpr line causes the compiler to ignore everything inside the condition if the condition is false, and then good optimizers will elide the function call altogether due to the empty body. Obviously, C# doesn't provide that fine level of control over the compiler/optimizer, nor are you permitted to use primitives like bool in a generic, nor can you provide application- or library-wide aliases via a using statement.

So I think I'll have to settle for a mix of what I listed above in the C# snippet and the API duplication + attributed method with forwarding implementation as my solution, barring any other means of imitating the posted C++.
 
Well, if you are willing to give up performance for the sake of convenience, then taking advantage of C# 8's default interface implementation, and using the Null Object pattern, I came up with this:
C#:
using System;
using System.Diagnostics;

namespace TestDBC
{
    public interface IVerify
    {
        public void IsGreaterThan(int actual, int minimum)
        {
            if (!(actual > minimum))
                throw new InvalidOperationException($"Actual value '{actual}' is not greater than minimum value '{minimum}'.");
        }
    }

    public interface IVerifyWithDebug : IVerify
    {
        IVerify Debug { get; }
    }

    class RealVerify : IVerify
    {
    }

    class NullVerify : IVerify
    {
        public void IsGreaterThan(int lhs, int rhs) { }
    }

    class VerifyBase : IVerifyWithDebug
    {
#if DEBUG
        public IVerify Debug { get; } = new RealVerify();
#else
        public IVerify Debug { get; } = new NullVerify();
#endif
    }

    public static class Contracts
    {
        public static IVerifyWithDebug Expects { get; } = new VerifyBase();
        public static IVerifyWithDebug Ensures { get; } = new VerifyBase();
    }

    class Program
    {
        static void Main(string[] args)
        {
            Contracts.Expects.IsGreaterThan(2, 1);
            Contracts.Expects.Debug.IsGreaterThan(2, 1);
            Contracts.Ensures.IsGreaterThan(2, 1);
            Contracts.Ensures.Debug.IsGreaterThan(2, 1);
        }
    }
}

The only serious code duplication you would have to deal with is manually re-declaring all the IVerify methods with empty bodies for the NullVerify null object.

There is a way to automate generating all those empty bodied methods by using the built in T4 templates, but it will require that the IVerify interface live in a separate assembly that gets compiled before this project that uses the T4 template. The idea is to reflect over the methods of the interface (e.g. typeof(IVerify).GetMethods()) and construct the appropriate C# code to go into the text generated by the template.

As I mentioned above, there is a performance cost to be paid since you'll be dealing with virtual function calls due to the interfaces, as opposed to your original approach of using static method calls. Furthermore, there is no opportunity for the C# compiler to optimize away calls to the null object, unlike with the use of conditional code.
 
Back
Top Bottom