Use of Assertions

D

Divick

Hi,
is it a nice idea to do assetion checks for method arguments ? I
am currently redesigning a piece of code. Now the problem is that there
are some assumptions for the method arguments that the code makes. It
is not checking the validity of the arguments everywhere because that
would lead to performance penalty. So I am think that at least
assertions will be able check the arguments at least for debug version
to verify the design. But now it means that I put the assertions
everywhere in the code, something like below:

Code with out checks

func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
ptr2->do something...
ptr1->call some method(ptr2);
}

Code with assertions
func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
assert( ptr1!= NULL && ptr2 != NULL); // And do this for all
functions with arguments everywhere
ptr2->do something...
ptr1->call some method(ptr2);
}

so my questions really is : Is it a good idea to put the assertions for
the function arguments like shown above? Why or why not?

Thanks,
Divick
 
G

Gianni Mariani

Divick said:
Hi,
is it a nice idea to do assetion checks for method arguments ? I
YES.

....
}

Code with assertions
func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
assert( ptr1!= NULL && ptr2 != NULL); // And do this for all

assert( ptr1 )
assert( ptr2 )

Validate *each* argument rather than have one long expression.

NULL *is* 0 is C++. I don't use NULL any more (personal preference).

functions with arguments everywhere
ptr2->do something...
ptr1->call some method(ptr2);
}

so my questions really is : Is it a good idea to put the assertions for
the function arguments like shown above? Why or why not?

It's a good idea because:

a) It documents your assumptions and enforces them (at least in debug).
b) It catches errors early (which is always desirable).
 
A

Alf P. Steinbach

* Divick:
Hi,
is it a nice idea to do assetion checks for method arguments ? I
am currently redesigning a piece of code. Now the problem is that there
are some assumptions for the method arguments that the code makes. It
is not checking the validity of the arguments everywhere because that
would lead to performance penalty. So I am think that at least
assertions will be able check the arguments at least for debug version
to verify the design. But now it means that I put the assertions
everywhere in the code, something like below:

Code with out checks

func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
ptr2->do something...
ptr1->call some method(ptr2);
}

Code with assertions
func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
assert( ptr1!= NULL && ptr2 != NULL); // And do this for all
functions with arguments everywhere
ptr2->do something...
ptr1->call some method(ptr2);
}

so my questions really is : Is it a good idea to put the assertions for
the function arguments like shown above?
No.


Why or why not?

Use reference arguments where you don't intend to support NULL-values.
 
B

Ben Pope

Divick said:
Hi,
is it a nice idea to do assetion checks for method arguments ? I
am currently redesigning a piece of code. Now the problem is that there
are some assumptions for the method arguments that the code makes. It
is not checking the validity of the arguments everywhere because that
would lead to performance penalty.

1st priority: Correctness.
2nd priority: Correctness!

Much lower priority: Performance.

Always validate the arguments, if there IS a performance penalty convert
the ones that matter to assertions.

If the input comes from the user, or a file or something, then
assertions are not really a suitable option. Validate those things ASAP
to contain the problem.

Ben Pope
 
D

Divick

Use reference arguments where you don't intend to support NULL-values.
Could you please give an example?

Seems like people have different opinions about this. Confused...:(

Divick
 
J

Jurko Gospodnetic

Hi Divick
Could you please give an example?

Seems like people have different opinions about this. Confused...:(

I do not think many people have different opinions on this. :)

Those who said that you should use assertions to make sure
your pointer parameters are not 0 were assuming you had a
reason for using pointers in the first place. What Alf said was
that you the question of whether to use assertions for this should
not be an issue if you do not need pointers here but can use
references.

In other words....
1. use assertions where needed.
2. use references instead of pointers wherever possible.

Just my two cents worth... and I hope it helps...

Best regards,
Jurko Gospodnetic
 
D

Divick

Those who said that you should use assertions to make sureOk, that helps. Now I understand what Alf was trying to say.

Thanks a lot,
Divick
 
J

Jacek Dziedzic

Divick said:
Hi,
is it a nice idea to do assetion checks for method arguments ?

Yes! Better safe than sorry.

If you are worried about performance (better support this
with an actual time-test, rather than thinking "this could
be too slow"), you might have two styles of asserts, like

Assert(...)
and
CostlyAssert(...)

that would be turned on/off independently with preprocessor
stuff like

#define WANT_ASSERTS
#define WANT_COSTLYASSERTS

Then you could leave Asserts on for both debug and release
versions and turn CostlyAsserts only for debugging.

HTH,
- J.
 
G

Gianni Mariani

Jacek said:
Yes, but what about problems like that which was discussed
recently:

http://groups.google.com/group/comp...p:comp.lang.c++&rnum=1&hl=en#0c93d210e3c2b5cb

That's a gem.

Yes, function overloading with templates and the special meaning of
literal 0 gets "overloaded".

It's too late now, but I think the language rules around the 0 literal
and null pointers to now be a bad idea. The NULL macro provides no help
here from a readability perspective, so I think that's a bad idea as
well (IMHO).
 
G

Greg

Divick said:
Hi,
is it a nice idea to do assetion checks for method arguments ? I
am currently redesigning a piece of code. Now the problem is that there
are some assumptions for the method arguments that the code makes. It
is not checking the validity of the arguments everywhere because that
would lead to performance penalty. So I am think that at least
assertions will be able check the arguments at least for debug version
to verify the design. But now it means that I put the assertions
everywhere in the code, something like below:

Code with out checks

func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
ptr2->do something...
ptr1->call some method(ptr2);
}

Code with assertions
func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
assert( ptr1!= NULL && ptr2 != NULL); // And do this for all
functions with arguments everywhere
ptr2->do something...
ptr1->call some method(ptr2);
}

so my questions really is : Is it a good idea to put the assertions for
the function arguments like shown above? Why or why not?

One way to look at a function call is as a contract between two
parties: the caller promises that certain things will be true before
making the function call (these are known as the preconditions), while
the callee (the function being called) makes certain promises about
what will be true after the function call completes (these known as the
postconditions). Assertions are used during development to check that
both sides are holding up their ends of bargain. And when errors are
detected, it is clear whether the error is located in the client's code
or in the function being called.

In this case, an assert that checks for NULL pointer parameters would
mean that the client has promised never to pass a NULL pointer as a
parameter. So a precondition of calling this routine is that all
pointer parameters be non-NULL. But much of the reason for passing an
argument by pointer is to allow certain values to be missing (or
optional). So if the value must be present it makes more sense to
declare the function with a reference parameter, since doing so better
communicates to the client the necessary preconditions. And if a
reference is for some reason impractical, at least the function
declaration could use a typedef, for instance an IntRef instead of an
int * to help convey to the caller that although the parameter type is
in fact a pointer, it is expected to refer to an extant instance of the
pointer type and not be NULL.

A great many bugs in software can be traced to vague notions about a
function's preconditions and postconditions. Clearly defining both, and
using assertions to verify compliance during development are two of the
most effective ways to assure quality in the finished application.

Greg
 
D

davidrubin

Divick said:
Hi,
is it a nice idea to do assetion checks for method arguments ? I
am currently redesigning a piece of code. Now the problem is that there
are some assumptions for the method arguments that the code makes. It
is not checking the validity of the arguments everywhere because that
would lead to performance penalty. So I am think that at least
assertions will be able check the arguments at least for debug version
to verify the design. But now it means that I put the assertions
everywhere in the code, something like below:

Code with out checks

func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
ptr2->do something...
ptr1->call some method(ptr2);
}

Code with assertions
func1(Ptr1 * ptr1, Ptr2 * ptr2)
{
assert( ptr1!= NULL && ptr2 != NULL); // And do this for all
functions with arguments everywhere
ptr2->do something...
ptr1->call some method(ptr2);
}

so my questions really is : Is it a good idea to put the assertions for
the function arguments like shown above? Why or why not?

In this particular case, it's not a good idea to check parameters. All
you need to do is specify in the contract of your interface that the
behavior is undefined unless the parameters are valid. In most cases,
you should assume that the behavior is undefined if you pass a null
pointer where a pointer argument is expected. Thus, you typically
specify when you *can* pass a null pointer, rather than when you can't.

The place you do want to use assertions is to verify invariants. For
example, if you have a class that represents a positive integer, you
want to assert that the representation is a positive integer. Usually
you can do this in the destructor. This lets you use the class without
much performance penalty, but still catch "impossible" errors.
 
D

davidrubin

Greg said:
But much of the reason for passing an
argument by pointer is to allow certain values to be missing (or
optional). So if the value must be present it makes more sense to
declare the function with a reference parameter, since doing so better
communicates to the client the necessary preconditions.

I have to disagree with this. Using a (modifiable) reference argument
to enforce the precondition that a valid (i.e., "non-null") argument
must be supplied obfuscates the possibility that the value will be
modified. OTOH, any time a non-const pointer is used as an argument,
the caller must always assume that the value will be modified. This is
a long-standing opinion.
And if a
reference is for some reason impractical, at least the function
declaration could use a typedef, for instance an IntRef instead of an
int * to help convey to the caller that although the parameter type is
in fact a pointer, it is expected to refer to an extant instance of the
pointer type and not be NULL.

This kind of typedef is of no use to anyone. In no way does it imply
that the parameter cannot by NULL. In fact, it doesn't even indicate
that the parameter is a pointer. It just obfuscates the interface.
A great many bugs in software can be traced to vague notions about a
function's preconditions and postconditions. Clearly defining both, and
using assertions to verify compliance during development are two of the
most effective ways to assure quality in the finished application.

I do agree with this. All you need is a clearly defined contract, and
possibly some assertions (to verify invariants).
 
R

roberts.noah

I have to disagree with this. Using a (modifiable) reference argument
to enforce the precondition that a valid (i.e., "non-null") argument
must be supplied obfuscates the possibility that the value will be
modified. OTOH, any time a non-const pointer is used as an argument,
the caller must always assume that the value will be modified. This is
a long-standing opinion.

There's no reason why a reference has to be modifiable. Pointer or
reference, both cases you use const to mean, "I'm not going to modify
this."
 
G

Greg

I have to disagree with this. Using a (modifiable) reference argument
to enforce the precondition that a valid (i.e., "non-null") argument
must be supplied obfuscates the possibility that the value will be
modified. OTOH, any time a non-const pointer is used as an argument,
the caller must always assume that the value will be modified. This is
a long-standing opinion.

Why would the client be calling the function unless the client knows
the reason for calling the routine and what the routine does? If the
client knows what and why it it is calling a function, than the fact
that some parameters may be references whose value may change is all
well and good, since that type of change is precisely why the function
is being called.

The idea that it must be clear whether a parameter in a function call
is a pointer or a reference or a value is a crutch left over from C.
Such an emphasis simply means that the program isn't really sure what
it is doing and has to limit the bad consequences that flow from that
fact.
This kind of typedef is of no use to anyone. In no way does it imply
that the parameter cannot by NULL. In fact, it doesn't even indicate
that the parameter is a pointer. It just obfuscates the interface.

This technique is commonly used in many well known and widely used
APIs. Such a typedef is usually called a "Handle", that is, a reference
to some (often opaque) data structure that the client passes to various
routines in an API. A client needs a valid Handle in order to call
these routines. It cannot pass NULL even though the Handle's type is in
fact a pointer.

It is far more important to focus on the meaning of the parameters to a
function call rather than their form. Fixating on pointers vs.
references vs. value is the wrong emphasis since it tries to limit what
can happen in the function call. Instead the proper focus should be on
what the client can expect to be true after the function call
completes.

Greg
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top