I think I've blogged on this one before, but think it is worth mentioning, since we touched on it during the First Year programming lecture today.
Consider the ReadNumber method above. It is designed to make our lives easier, so that if I want to get the number of players for my game I can just call the method:
int noOfPlayers = ReadNumber ("How many players? : ", 2,4);
The idea is that the method prints the prompt and gets a number from the user in the range 2-4. If the user gives a value outside the range the method politely asks for another value.
This is a neat method. But what happens if I make a mistake when I call it:
int noOfPlayers = ReadNumber ("How many players? : ", 4,2);
This means that the minimum is now higher than the maximum. Which is wrong. During the lecture I mentioned this possibility and suggested this rather firm approach inside the method when it runs:
if (min >= max)
throw new Exception("Invalid min and max range");
The code above makes the method fail if the minimum and maximum are incorrect. And by fail I mean stop the program from working. I suggested that in this situation the method can't do anything but fail, since it is operating under a failed premise.
After the lecture one of the First Year (splendid bunch by the way) came up to me and suggested that one solution would be for the method to just swap the minimum and maximum values round if the method discovers that they are the wrong way round. The test is easy to make and swapping the values takes no time at all. And the method is then going to continue. So why not?
Because this is the kind of idea I call "Half way good and all the way bad". We are making a very, very, dangerous assumption, which is that the mistake was that the person using the method has got the min and max the wrong way round. Consider this code:
int coreTemp= ReadNumber ("Reactor core temperature? : ", 20,40);
This code is asking the user for the reactor core temperature (whatever that is). But what happens if when the method is written the programmer misses out a zero when typing it in:
int coreTemp= ReadNumber ("Reactor core temperature? : ", 20,4);
Now the minimum is much higher than the maximum. If my program swaps these values over it will be asking for a value between 4 and 20, which is much too low and might cause really bad things to happen. The clever swapping trick has now changed a typing error to produce a fault that is potentially very dangerous.
If the method stops the program when it is not used correctly the programmer is guaranteed to spot it. But if we do the swapping thing we could end up with strangely broken programs out there. So I'm very keen to cause the maximum damage when my methods are told wrong things.
Actually, the best way to solve this problem is to use a lovely feature of C# which lets you name each argument to a method call:
NoOfPlayers = ReadNumber(prompt:"Age : ", min:10, max:100);
In this call of ReadNumber we actually identify each parameter by name, rather than using their position in the list to indicate what they mean. I'm a big fan of naming arguments like this, since it also makes it much clearer to someone reading the code what is actually going on.