Peter N Lewis wrote:
That's the point. My assertions tend to be things like:
Assert( ValidDataStructure( x ) );
ValidDataStructure might be a very expensive call, it might parse through the entire data structure looking for holes in it.
[...]
GPC also makes this more challenging because you can't define a macro in any given unit for asserting the validity of data structures because that macro is not propagated into the using units. For example, in the interface my hypothetical Lists unit above, I would add something like:
{$ifc not do_debug} {$definec AssertValidList( list )} {$elsec} {$definec AssertValidList( list ) AssertValidListCode( list, SrcFile, SrcLine )} {$endc}
{$ifc do_debug} procedure AssertValidListCode( list: ListType; source: String; line: Integer ); {$endc}
but that does not work in GPC. My solution has been to use a prefix file and copy all such macro definitions to the prefix file. This is less than ideal since it breaks the modularity. Perhaps someone has a better solution for me, but it's the best I can come up with so far.
GCC/GPC supports the `const' attribute for functions which means:
: `const' : Many functions do not examine any values except their arguments, : and have no effects except the return value. Basically this is : just slightly more strict class than the `pure' attribute above, : since function is not allowed to read global memory. : : Note that a function that has pointer arguments [or reference parameters in Pascal] : and examines the data pointed to must _not_ be declared : `const'. Likewise, a function that calls a non-`const' : function usually must not be `const'. It does not make sense : for a `const' function to return `void'.
The important thing here is that it tells the compiler that the function has no side effects so `Assert' can safely remove the call.
In case the actual checking function does not fit the `const' description (which will often be the case, I suppose), you can use a conditional as above.
This one does not produce any code for the `Assert':
{$define do_debug False}
unit U;
interface
type ListType = ^TListType; TListType = record Next: ListType; a: Integer; end;
function IsValidList (List: ListType): Boolean; {$ifc not do_debug} attribute (const); {$endc}
implementation
function IsValidList (List: ListType): Boolean; begin {$ifc not do_debug} IsValidList := True {$elsec} { actual checks ... } IsValidList := List <> nil {$endc} end;
end.
{$no-assert}
program Foo;
uses U;
var a: ListType;
begin Assert (IsValidList (a)) end.
Frank