Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Conditional Interpretation?

by earcam (Initiate)
on Feb 01, 2006 at 02:56 UTC ( #526948=perlquestion: print w/replies, xml ) Need Help??

earcam has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks, Does anyone know if there's the equivalent for C/C++ preprocessor directives, for conditional compilation, eg:
#ifdef DEBUG ... #endif
I have OO modules (for mod_perl) and once in production certain expensive checks can (and need to) be omitted. Is there something that allows blocks of code in PM files to be ignored if another something is set in calling scripts? I don't want to add loads of tests for a global var. Something in POD maybe? I'd greatly appreciate any help or pointers. thanks, earcam

Replies are listed 'Best First'.
Re: Conditional Interpretation?
by ikegami (Pope) on Feb 01, 2006 at 03:13 UTC

    Two ways.

    1. You can tell Perl to use the C preprocessor with the command line option -P. Be sure to read the limitations of the switch, as documented in perlrun.

    2. Use constant folding to remove the checks at runtime. In the following, notice how the debug code is removed when (and only when) a constant expression is used in the if:

    >perl -MO=Deparse -e "$DEBUG = 0; print(qq{debug\n}) if $DEBUG; print( +qq{end\n})" $DEBUG = 0; print "debug\n" if $DEBUG; print "end\n"; -e syntax OK >perl -MO=Deparse -e "use constant DEBUG => 0; print(qq{debug\n}) if D +EBUG; print(qq{end\n})" use constant ('DEBUG', 0); '???'; print "end\n"; -e syntax OK
Re: Conditional Interpretation?
by ptum (Priest) on Feb 01, 2006 at 03:00 UTC
Re: Conditional Interpretation?
by gryphon (Abbot) on Feb 01, 2006 at 03:06 UTC

    Greetings earcam,

    One of the things we did was to use a constant (or a bitwise and set of constants) inside a right-side if conditional for whether we had debug statements work. The compiler optimizes away the entire line at run-time if the constant conditional is false.

    do_something() if ($CONSTANT); do_something_else() if ($CONSTANT & $ANOTHER_CONSTANT);

    Is this what you're looking for?

    gryphon Development Manager (WDDC)
    code('Perl') || die;

      Constants don't have leading dollar signs.

      do_something() if (CONSTANT); do_something_else() if (CONSTANT & ANOTHER_CONSTANT);

      If there's a dollar sign, it's not a constant, and Perl won't optimize it away.

Re: Conditional Interpretation?
by blazar (Canon) on Feb 01, 2006 at 11:53 UTC

    In addition to the other suggestions that have already been given to you, it is worth mentioning that you would better provide a per-module conditional debugging facility. You may want to activate it like

    use My::Module DEBUG => 1;

    or more easily from the implementation POV:

    use My::Module; # ... $My::Module::DEBUG = 1;

    If you're concerned that for every debugging info there will be a condition to be checked, for the most critical cases you may write two versions of a sub: one for regular use and one for debugging and call them dereferencing a coderef to the appropriate one assigned to a variable, or perhaps, if you really need to, you may mangle the symbol table. But please do that only if you know what you're doing

Re: Conditional Interpretation?
by glasswalk3r (Friar) on Feb 01, 2006 at 13:50 UTC

    Maybe this is not exactly what you're looking for, but if you want to add logging to the OO modules depending on a value, them you should check the Log4Perl module.

    Alceu Rodrigues de Freitas Junior
    "You have enemies? Good. That means you've stood up for something, sometime in your life." - Sir Winston Churchill
Re: Conditional Interpretation?
by salva (Abbot) on Feb 01, 2006 at 14:54 UTC
    you are looking for assertions, unfortunatelly they only work on the unstable versions of perl. assertions::compat is also available but it requires you to test constants explicitelly as ...
    dbg and expensive_test();

    Another similar module is ctflags (that stands for "compile time flags"), it is overly complex with too many options... but for what you need:

    In some place, at the beggining of your script, include this code to set flags from an environment variable:

    use ctflags::parse ns => "myapp:debug", env=>'MYAPPDEBUG';
    then in every module where you want to conditionally execute something add:
    use ctflags prefix=>'dbg_', 'myapp:debug:*'; dbg_a and print "a flag is on\n"; dbg_b and print "b flag is on\n"; dbg_c and print "c flag is on\n";
    Finally, if you call your script as
    $ MYAPPDEBUG=ac perl
    it will output
    a flag is on c flag is on
Re: Conditional Interpretation?
by earcam (Initiate) on Feb 01, 2006 at 23:40 UTC
    Thanks for all suggestions, I will investigate these further and report back. To clarify my problem here's an example
    sub someMethod { my $this = isa( ref $_[0], 'Package::Path::Module' ) ? shift : die( +'Package::Path::Module::someMethod called with uninstantiated object. +'); # ... }
    Replaced with something like:
    sub someMethod { =PERL_INCLUDE my $this = isa( ref $_[0], 'Package::Path::Module' ) ? shift : die( +'Package::Path::Module::someMethod called with uninstantiated object. +'); =PERL_INCLUDE # ... }
    With the shebang in calling script stating something like:
    #!/usr/bin/perl -Wall -POD_PERL_INCLUDE
    to include the POD section.

    The instantiation check exists in every object/instance method (with a similar check for class-only methods) - with a massive number of subroutine calls, this really hits performance across all the code.
    ( I know there's quicker ways of checking correct instantiation, but it's still a check that becomes unnecessary for production code )
    There are many other checks that could also be excluded.

    Our logging already works using sub refs to a dummy subroutine to avoid endless if($obj->{'DEBUG'}){ ... } calls so no gains to be made there.

    I think we may have exhausted the majority of optimisation tricks - avoiding these kind of checks shaves off approximately 1/4 of the total run time.
    I found this (via "man perlbot")
    1 Do not attempt to verify the type of $self. That'll break if the class is inherited, when the type of $self is valid but its pack- age isn't what you expect. See rule 5.
    2 If an object-oriented (OO) or indirect-object (IO) syntax was used, then the object is probably the correct type and there's no need to become paranoid about it. Perl isn't a paranoid language anyway. If people subvert the OO or IO syntax then they probably know what they're doing and you should let them do it. See rule 1.

    Though object orientated, we've avoided inheritance, but I still disagree with the above because not checking how a method is called has already caused hours of scratched heads and bug hunting - so we do need these checks at dev level, but only at dev...

    Thanks for all comments.


Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://526948]
Approved by McDarren
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others chilling in the Monastery: (7)
As of 2020-12-04 08:40 GMT
Find Nodes?
    Voting Booth?
    How often do you use taint mode?

    Results (58 votes). Check out past polls.