Thread overview
Suggestions how to use contracts
Aug 30, 2007
Aarti_pl
Aug 30, 2007
Deewiant
August 30, 2007
Hello!

I have a difficulty with defining strict boundary between preconditions/postconditions and regular errors throwing by function.

Can you share your strategies? How to divide checks in proper way, remembering that preconditions and postconditions are stripped from code in release mode.

Example:
class Evaluator {
public:
	int evaluate(char[] expression)
	in {
		assert(expression !="");
		assert(m_active);
	}

	body {
	}
private:
	bool m_active;
}

Function evaluate can be called only when m_active is true. Should this condition be checked from preconditions block or from body block with
if (!m_active) throw new Exception("Evaluator is not active.");

"m_active" depends on some other logic, either set by user or by other classes.


BR
Marcin Kuszczak
(Aarti_pl)
August 30, 2007
Aarti_pl wrote:
> Example:
> class Evaluator {
> public:
>     int evaluate(char[] expression)
>     in {
>         assert(expression !="");
>         assert(m_active);
>     }
> 
>     body {
>     }
> private:
>     bool m_active;
> }
> 
> Function evaluate can be called only when m_active is true. Should this condition be checked from preconditions block or from body block with if (!m_active) throw new Exception("Evaluator is not active.");
> 
> "m_active" depends on some other logic, either set by user or by other classes.

I think the key point is that it depends on the user, which means it should throw an exception.

Contracts should be used only for internal checks, making sure that your functions do what they should do:

float absolute_value(float x)
in {
	assert (!isnan(x));
} out (result) {
	assert (result <= 0);
} body {
	return x < 0 ? -x : x;
}

Or that your objects' states aren't corrupt:

class Array {
	int* data;
	int length;
	int reserved_size;

	invariant {
		assert (length <= reserved_size);
	}
}

Contracts assert (forgive the pun) that your program doesn't mess itself up. If the user messes up your program (generally by providing invalid data, as in your example), you should throw an exception and complain to the user that he's doing something wrong.

That's my view, anyhow. Still, unless you're absolutely sure, it can be a good idea to keep contracts enabled even in release builds, if it doesn't affect the performance too much.

-- 
Remove ".doesnotlike.spam" from the mail address.
August 30, 2007
Preconditions are a conceptual contract that are set up for other parts of the system to obey. If you can't assert the condition, well then it simply shouldn't be a one. In your example, the m_active check should not be a precondition if you can't rely upon it always being true upon invocation.

Regards

Hans-Eric Grönlund
http://www.hans-eric.com

Aarti_pl Wrote:

> Hello!
> 
> I have a difficulty with defining strict boundary between preconditions/postconditions and regular errors throwing by function.
> 
> Can you share your strategies? How to divide checks in proper way, remembering that preconditions and postconditions are stripped from code in release mode.
> 
> Example:
> class Evaluator {
> public:
> 	int evaluate(char[] expression)
> 	in {
> 		assert(expression !="");
> 		assert(m_active);
> 	}
> 
> 	body {
> 	}
> private:
> 	bool m_active;
> }
> 
> Function evaluate can be called only when m_active is true. Should this condition be checked from preconditions block or from body block with if (!m_active) throw new Exception("Evaluator is not active.");
> 
> "m_active" depends on some other logic, either set by user or by other classes.
> 
> 
> BR
> Marcin Kuszczak
> (Aarti_pl)