www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Suggestions how to use contracts

reply Aarti_pl <aarti interia.pl> writes:
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)
Aug 30 2007
next sibling parent Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
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.
Aug 30 2007
prev sibling parent =?ISO-8859-1?Q?Hans-Eric_Gr=f6nlund?= <hasse42g gmail.com> writes:
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)

Aug 30 2007