views:

303

answers:

9

Do you check for data validity in every constructor, or do you just assume the data is correct and throw exceptions in the specific function that has a problem with the parameter?

+12  A: 

A constructor is a function too - why differentiate?

Creating an object implies that all the integrity checks have been done. It's perfectly reasonable to check parameters in a constructor and throw an exception once an illegal value has been detected.

Among all this simplifies debugging. When your program throws exception in a constructor you can observe a stack trace and often immediately see the cause. If you delay the check you'll then have to do more investigation to detect what earlier event causes the current error.

sharptooth
+2  A: 

It's always better to have a fully-constructed object with all the invariants "satisfied" from the very beginning. Beware, however, of throwing exceptions from constructor in non-managed languages since that may result in a memory leak.

Anton Gogolev
+1  A: 

If you throw in the constructor, the stack trace is more likely to show where the wrong values are coming from.

Damien_The_Unbeliever
A: 

I agree with sharptooth in the general case, but there are sometimes objects that can have states in which some functions are valid and some are not. In these situations it's better to defer checks to the functions with these particular dependencies.

Usually you'll want to validate in a constructor, if only because that means your objects will always be in a valid state. But some kinds of objects need function-specific checks, and that's OK too.

Welbog
That's the same. True that not all methods can be legally called in any object state. But also you can often identify the combinations of parameter values that can come together into constructor and throw exceptions if any other combinations come.
sharptooth
Also, if your object has some methods which are always valid and some which are not, you might consider if your object is too big. Maybe it should be split up?
sleske
+2  A: 

I always coerce values in constructors. If the users can't be bothered to follow the rules, I just silently enforce them without telling them.

So, if they pass a value of 107%, I'll set it to 100%. I just make it clear in the documentation that that's what happens.

Only if there's no obvious logical coercion do I throw an exception back to them. I like to call this the "principal of most astonishment to those too lazy or stupid to read the documentation".

paxdiablo
sounds interesting, but doesn't this lead to code which behaves unexpected some times?
Homes2001
Yes, but only to those who haven't read the doco :-)
paxdiablo
uhm... I think this may lead to code hard to use/understand: there are many cases in which I'd have a hard time spotting the "obvious logical coercion"
Manrico Corazzi
@Manrico: It's only hard to use/understand if the aforementioned documentation has been ignored... if caveats of the API aren't understood, then surely you should expect unexpected results? I doubt I'd use coercion, but +1 for the documentation regarding side effects of incorrect use.
BenAlabaster
Sound terrible. The caller really should know they made a mistake - coercing encourages ambiguity and sloppy programming, rather than sensible accurate usage of the api.
mP
Shouldn't an API be self-documenting, as far as possible? And shouldn't you fail as quickly as possible if/when you know that something is wrong?
LukeH
@mP, sensible and accurate use of the API is to use it as it was intended. There is no ambiguity here, the effects of calling with incorrect arguments are fully specified.
paxdiablo
@Luke, there's nothing "wrong" - the code is acting as documented. Keep in mind this is what *I* tend to do (as the question asked) - I'm not saying you should do it or even that it's right. You need to make up your own mind how you code. If you don't like my style, steer clear of my code :-)
paxdiablo
That wasn't meant to sound insulting, just stating that people will avoid libraries or products that don't act as they think they should. That'll limit my market but it hasn't affected me yet (that I know of).
paxdiablo
A: 

This is a difficult question. I have changed my habit related to this question several times in the last years, so here are some thoughts coming to my mind :

  • Checking the arguments in the constructor is like checking the arguments for a traditional method... so I would not differentiate here...
  • Checking the arguments of a method of course does help to ensure parameters passed are correct, but also introduces a lot of more code you have to write, which not always pays off in my opinion... Especially when you do write short methods which delegate quite frequently to other methods, I guess you would end up with 50 % of your code just doing parameter checks...
  • Furthermore consider that very often when you write a unit test for your class, you don't want to have to pass in valid parameters for all methods... Quite often it does make sense to only pass those parameters important for the current test case, so having checks would slow you down in writing unit tests...

I think this really depends on the situation... what I ended up is to only write parameter checks when I know that the parameters do come from an external system (like user input, databases, web services, or something like that...). If data comes from my own system, I don't write tests most of the time.

Homes2001
About your third point: why would do like to test something that will never happen? If you check the parameters in the constructor then the values will never be the wrong value. So you don't have to test there. Only test the constructor with wrong parameters.
Peter Stuifzand
A: 

I always try to fail as early as possible. So I definitively check the parameters in the constructor.

idstam
"I always try to fail as early as possible" = "int main(void) {raise(6); ... }"? :-)
paxdiablo
At least it compiled :)
idstam
A: 

In theory, the calling code should always ensure that preconditions are met, before calling a function. The same goes for constructors.

In practice, programmers are lazy, and to be sure it's best to still check preconditions. Asserts come in handy there.

Example. Excuse my non-curly brace syntax:

// precondition b<>0
function divide(a,b:double):double;
begin
  assert(b<>0); // in case of a programming error. 
  result := a / b;
end;

// calling code should be:
if foo<>0 then
  bar := divide(1,0)
else
  // do whatever you need to do when foo equals 0

Alternatively, you can always change the preconditions. In case of a constructor this is not really handy.

// no preconditions.. still need to check the result
function divide(a,b:double; out hasResult:boolean):double;
begin
  hasResult := b<>0; 
  if not hasResult then
    Exit;
  result := a / b;
end;

// calling code:
bar := divide(1,0,result);
if not result then
  // do whatever you need to do when the division failed
Wouter van Nifterick
Hang on a minute, that's not just C without braces. It's Pascal! Watch out guys, he's got a Pascal compiler. Run for your lives.
paxdiablo
A: 

Always fail as soon as possible. A good example of this practice is exhibited by the runtime .. * if you try and use an invalid index for an array you get an exception. * casting fails immediately when attempted not at some later stage.

Imagine what a disaster code be if a bad cast remained in a reference and everytime you tried to use that you got an exception. The only sensible approach is to fail as soon as possible and try and avoid bad / invalid state asap.

mP