I agree with what you've said about using assertions to verify that contracts are not being violated. But I also believe that assertions should not be used to validate method arguments. On one hand, it's okay to specify assert x != null;. On the other hand, assert x != null; should not be specified. I realize this is confusing, until one figures out why assertions exist.
I believe that assertions are a tool for helping me deal with my own coding mistakes. I do not believe they are appropriate for dealing with the coding mistakes of others. I would use assertions to prove the correctness of my code. I would not use
them to validate method arguments supplied by someone else. I wouldn't do that because failure to enable assertions would most likely prevent another developer from figuring out the cause of a problem, and perhaps I would be blamed when the real problem exists with the other developer passing invalid arguments.
In the article, I'm taking the perspective where someone else is passing arguments to sort(). In that case, I would not use an assertion. Instead, I would either implicitly throw a NullPointerException, or insert an if statement that explictly throws a NullPointerException -- perhaps with a good description of what is going on. I
should have been clear on this in the article and I apologize for any confusion.
Perhaps another example might be helpful. Suppose I want to create a custom Swing-based bar chart component, where each bar is split into two side-by-side halves. The left half shows the amount of a loan payment that goes toward paying off the principal on a loan. The right half shows the amount of a loan payment that pays down the interest accumulated during one month of the loan. In addition to taking a JFrame argument that identifies the parent frame component, my BarChart class's constructor takes a pair of floating-point array arguments that identify interest paid and
principal paid over the term of the loan. Check out the source code below:
public class BarChart extends JPanel
{
private float [] intPaid;
private float [] princPaid;
public BarChart (JFrame parent, float [] intPaid, float [] princPaid)
{
assert parent != null;
assert intPaid != null;
assert princPaid != null;
assert intPaid.length == princPaid.length : "different lengths";
this.intPaid = intPaid;
this.princPaid = princPaid;
// Other stuff
}
}
BarChart has a number of contracts. First, null must not be passed as an argument value for the parent JFrame. Second, null must not be passed as an argument value for the interest paid array. Third, null must not be passed as an argument value for the principal paid array. Finally, the lengths of the arrays must be the same. Using
assertions to enforce these contracts is appropriate. While developing and testing my bar chart component, I want to catch any violations of these contracts, so I can fix them.
At some point, I'm going to want to ship this class to other developers. If I choose to rely on assertions, those developers pass illegal argument values, and assertions are not enabled, the illegal argument values will most likely not be detected (unless something in "Other stuff" betrays their presence) and a BarChart() object will be created. Later in the execution, a problem will undoubtedly occur because of a null frame, a null array, or mismatched array lengths.
Because I cannot assume that assertions will always be enabled by others who use my component, and because I don't want to get a bad reputation, I insert if statements that explicitly throw exceptions when invalid arguments are detected. I don't rely on assertions to do the job for me. |