develooper Front page | perl.perl5.porters | Postings from November 2002

[FEATURE] assertions

Thread Next
From:
Salvador Fandino
Date:
November 11, 2002 04:55
Subject:
[FEATURE] assertions
Message ID:
3DCFB698.6030705@yahoo.com
Hello,

I have modified perl source code to support assertions, ala C
assert macro. Attached to this mail is a patch for perl_current.


DESCRIPTION:

Briefly, I have done three things:

1. A new sub attribute 'assertion' is used to mark subs as
assertion code, i.e.:

   01  sub assert (&$) : assertion {
   02    &{$_[0]} or die "assertion failed: $_[1]";
   03  }
   04
   05  sub mysqrt ($) {
   06    my $val=shift;
   07    assert { $val>=0 } "arg to mysqrt has to be >= 0";
   08    sqrt($val);
   09  }
   10
   11  my $v=-4;
   12  my $s=mysqrt($v);
   13
   14  print "mysqrt($v)=$s\n";


2. I have added support for a new perl command line flag '-A' to
activate assertions:

   perl -A script.pl # runs assertions
   perl script.pl    # doesn't run assertions

arguments for assertion subroutines are not evaluated either,
unless the -A switch is used. You can think that assertion calls
are treated like that:

   # with -A switch from the command line
   my_assertion(@args)
   # is like ...
   (1 and my_assertion(@args))
   # that becomes
   my_assertion(@args)

   # with out -A
   my_assertion(@args)
   # is like
   (0 and my_assertion(@args))
   # that becomes
   0

As with prototypes, assertion behavior can be disabled calling
the sub with '&':

   &my_assertion(@args)

Assertion behavior is also ignored when the sub is called as a
method:

   $object->my_assertion(@args)



3. I have also modified perl debugger script (perl5db.pl) and
perl debugger internals to treat assertions as conditional
breakpoints. i.e., when the code above is run with the
debugger...

   $ PERLDB_OPTS=NonStop bin/perl -A -d ~/mysqrt.pl
   assertion failed: arg to mysqrt has to be >= 0
   main::mysqrt(/home/salva/mysqrt.pl:8):
   8:        sqrt($val);
     DB<1> l
   8==>      sqrt($val);
   9       }
   10
   11:     my $v=-4;
   12:     my $s=mysqrt($v);
   13
   14:     print "mysqrt($v)=$s\n";
   15
     DB<1>

.... the program stops just after the failed assertion at line 7
and the debugger commands can be used to inspect its state.

The debugger can also be configured to call DB::sub only when
assertions are called, this can result in a huge performance
improvement in some cases.

   $ PERLDB_OPTS='OnlyAssertions=1 frame=3 NonStop=1' \
   > bin/perl -A -d ~/mysqrt.pl
   Package /home/salva/mysqrt.pl.
   entering main::assert
   assertion failed: arg to mysqrt has to be >= 0
   exited main::assert
   8:        sqrt($val);
     DB<1>


Other feature added to the debugger is that it can trap assertion
errors and convert them to warnings. The WarnAssertions option is
used:

   $ PERLDB_OPTS='WarnAssertions=1 NonStop=1' bin/perl -A -d ~/mysqrt.pl
   assertion failed: arg to mysqrt has to be >= 0
   Can't take sqrt of -4 at /home/salva/mysqrt.pl line 8.
           main::mysqrt(-4) called at /home/salva/mysqrt.pl line 12
   $


IMPLEMENTATION DETAILS:

1. "assertion" attribute is implemented in the same way as
"method" or "locked", I have defined a new flag for CVs,
CVf_ASSERTION and the corresponding set of macros in
'cv.h'. Assertion behavior is implemented in function
Perl_ck_subr in 'op.c'.

2. assertion activation/deactivation is implemented with the help
of a new interpreter variable, PL_asserting that is set if -A is
in the command line.

3. there are two changes made to perl debugger internals :

- new flag for PL_perldb (or $^P), PERLDBf_ASSERTION to make
DB::sub be entered in assertion sub calls even if PERLDBf_SUB is
not set.

- new perl DB var $DB::assertion that is set to 1 at assertion
calls, so that the debugger can know if the current sub is an
assertion or not. For simplicity, the debugger has responsibility
to reset this var to 0.

There are also several changes made to perl5db.pl, to use the new
features. As a commodity I have also implemented a new command P
to change $^P in a friendly manner.



DISCUSSION:

I felt that Perl support for assertions was not good enough so I
bagan working in some ideas I had and this is the result.

By the way, I had to made some decisions that I want to expose
now.

- 'assertion' attribute:

I think it is not possible to do what I have done in an efficient
manner without adding support for this attribute in the perl C
core, I mean just using something like a MODIFY_CODE_ATTRIBUTES
sub.


- command line switch '-A'

assertions conditional execution can be simulated in perl with a
constant and the 'and' operator as in the Carp::Assert package

   DEBUG and assert($test);

but this do not solve how to activate then easily, several
approaches can be used, but the thing is that there is not any
standard/de-facto/common/etc. way to do it.


- assertions as static conditional breakpoints

I think this is a very powerful feature, programs will not die
anymore with an annoying message, but they will go directly to
the interactive debugger at the point where the error is. Then,
you will be able to inspect the internal status of the program
and even to correct the error and make the program continue.


- generalization of conditional execution

maybe the 'assertion' attribute is very specific, the conditional
execution of subroutines is not exclusive of assertions, it is
also very common for informative debug messages, as

   DEBUG and print(...);

so, maybe an attribute like 'call_if($condition)' could be used:

   package foo;
   sub debug : call_if($::debug=~/\bfoo\b/) {
      print STDERR @_
   }

but I have left this generalization out because the 'assertion'
attribute is also used to mark the subroutines for the debugger
so it would be needed anyhow.


- granularity of -A

'-A' switch is an all or nothing option, maybe something with
finer granularity as in the 'warnings' package could be thought,
but the thing is that assertion execution should be totally
controlled from the script execution options (command line or
environment vars.), it makes no sense to have to change the
source to activate/deactivate assertions.

Maybe '-A' could be used with a list of names

   perl -Alwp,mypackage script.pl

and in My::Package source...

   package My::Package;

   use assertions 'mypackage';

and assertions in My::Package would be executed only if
'mypackage' is passed in '-A'.


And that's all, now I am waiting for your comments and ideas, so
please, try the patch and tell me what you think.

Oops, just one last thing, please forgive me for my bad English,
but this is not what I use to speak :-(... and the same applies
for my perl C internals knowledge, I think that the
implementation is correct, but maybe I have forgotten something.

Bye,

   -Salva



Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About