8

Doing some research, it seems that people generally agree that arguments to public methods should be validated while private functions typically do not. This causes me to have some questions, but I have not been able to find a satisfactory answer so far.

Example:

public void DoSomething(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

Thoughts:

  1. What if the requirement of i to be non-negative changes inside DoWork()? The design risks leaving outdated validation checks in place. The programmer is responsible for adjusting the usage of a function that has changed, I know, but it leaves me wondering if there is a better way to minimize risk of error.

  2. What about different calls to DoWork() not from DoSomething()? Must we validate the arguments redundantly?

public void DoSomething(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

public void DoSomethingElse()
{
    int i = 5;
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

This can be cleaned up a little by putting the check into a function of its own. Then there is the risk that a new function making a call to DoWork(int i) will forget to validate i.

public void DoSomething(int i)
{
    ThrowIfIntegerIsNegative(i);

    double d = DoWork(i);
}

public void DoSomethingElse()
{
    int i = 5;
    ThrowIfIntegerIsNegative(i);

    double d = DoWork(i);
}

static void ThrowIfIntegerIsNegative(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");
}

private double DoWork(int i)
{
    double ret = ...; // some calculation
    return ret;
}

Is that at all better than this?

public void DoSomething(int i)
{
    double d = DoWork(i);
}

public void DoSomethingElse()
{
    double d = DoWork(5);
}

private double DoWork(int i)
{
    if (i < 0)
        throw new ArgumentOutOfRangeException("i");

    double ret = ...; // some calculation
    return ret;
}

Depending on the situation, these are some goals I am trying to achieve simultaneously:

  1. Have the argument validation in a single place (and possibly inside the function using the argument)
  2. Report an error sooner rather than later (might not want to have a bunch of code run for an hour just to fail at the end for some bad user input)
  3. Avoid validating arguments multiple times
  4. Avoid performance impact in release code

How do you strike a balance? What methodology has worked best for you? I would greatly appreciate any insight.

Daniel McClelland
  • 377
  • 1
  • 4
  • 13
  • CodeContracts would help. – Bob Vale Jun 06 '13 at 18:33
  • @BobVale The code must be portable via Mono, so I am not sure if Code Contracts are [fully supported](http://www.mono-project.com/Compatibility). I remember reading somewhere that using Spec# couples the code to Visual Studio, which is not necessarily a problem for now, but could very well be in the future. – Daniel McClelland Jun 06 '13 at 18:37
  • Code Contract's `Contract.Requires()` preconditions are supported in [`Mono 2.8`](http://www.mono-project.com/Release_Notes_Mono_2.8) along with a code rewriter to handle them properly - that by itself would be really useful. The MS one has a setting which controls whether to instrument public+private or only public methods, and you can select that differently between debug and release builds. I'd expect the Mono one to support that too. – Matthew Watson Jun 06 '13 at 18:49

3 Answers3

14

The logic behind validating arguments in public methods and not validating arguments in private ones goes roughly as follows:

  • When a public method is called with invalid arguments, it is a programming error outside your control.
  • When a non-public method is called with invalid arguments, it is a logical error within your control.

This logic is reasonable: there is no need to waste cycles on validating the arguments to methods that your module produces internally. Private methods, on the other hand, could always assume that their arguments are valid, because you are in control of all calls of private methods.

However, it is very beneficial to catch situations when these assumptions are violated. To that end, it is a very good idea to use run-time assertions in place of argument validation inside private methods. This catches invalid invocations from outside callers with exceptions, and alerts you to invalid invocations from your own methods with asserts.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I am having trouble following your last paragraph. It seems to me that argument validation and run-time assertions can be one and the same. These assertions could take the form of if-statements or perhaps Debug.Assert(). What is the point you are making? – Daniel McClelland Jun 14 '13 at 20:25
  • @DanielMcClelland The crucial difference between an assertion (e.g. `Debug.Assert`) and run-time argument checking is that they tell the reader of your code different things: checking an argument and throwing an exception says that the caller might pass you a wrong argument; an assertion, on the other hand, tells the reader that you have ensured that the argument is valid. Exceptions are for your callers; assertions are for you. In a sense, assertions are almost like "private exceptions": their purpose is to tell you that your assumptions about your code were wrong at some point. – Sergey Kalinichenko Jun 14 '13 at 20:33
  • @DanielMcClelland Jon Skeet wrote [a wonderful answer](http://stackoverflow.com/a/1276318/335858) with the details on the assertions vs. exceptions. He also mentions that assertions should be used to check arguments of private methods. – Sergey Kalinichenko Jun 14 '13 at 20:38
2

I like to validate with exceptions in public methods:

public void Foo(int i)
{
    if (i < 0)
      throw new ArgumentOutOfRangeException("i");

    double d = DoWork(i);
}

And I like to validate with Asserts in private methods:

private double DoWork(int i)
{
    System.Diagnostics.Debug.Assert(i >= 0);
    // ....
}
  1. It means duplicate validation in multiple public methods.
  2. It catches the invalid parameters as early as possible.
  3. Throwing an ArgumentOutOfRangeException exception due to invalid parameter inside the private method may be confusing to the caller of the public method due to differences in parameter names, etc.
  4. Often, your public methods do additional work before calling your private methods, so that work is saved.
  5. Use unit testing to ensure new methods don't miss any validation checks.

One additional thing to do is treat any protected method like a public method.

Edit:

This is an example of bad validation which violates #3 above:

public void Foo(int distanceInMetres)
{
    double d = DoWork(distanceInMetres * 1000);
}

private double DoWork(int distanceInMillimetres)
{
    if (distanceInMillimetres < 0)
      throw new ArgumentOutOfRangeException("distanceInMillimetres");
    // ....
}

If the caller to Foo sees the exception on the parameter "distanceInMillimetres", he will be confused because he called "Foo" which took a parameter named "distanceInMetres".

Matt Houser
  • 33,983
  • 6
  • 70
  • 88
1

Agree with dasblinkenlight statements about public and not public methods.

If you practice TDD, your private methods is just the result of refactoring code and extracting some pieces of public methods into private methods. So if you covered public methods with tests, your private methods will be automatically tested.

If you don't use TDD but want to verify that logic is not violated, you can use different techniques, for example - asserts (http://msdn.microsoft.com/en-us/library/ttcc4x86.aspx) or code contracts (http://msdn.microsoft.com/en-us/library/dd264808.aspx).

rpeshkov
  • 4,877
  • 3
  • 27
  • 43