📜 ⬆️ ⬇️

Goodbye if $ DEBUG!

I think any Perl programmer quite regularly adds auxiliary code to the program, which should not always be executed. This may be a debugging code, collection of statistics on the speed of work of different parts of the code, output to the log, etc. There are several problems with this code at once:
  1. It interferes with reading the main code. It slows down the execution of the program. Because of the first two reasons, it is often deleted as soon as the need for it disappears ... only, unfortunately, the need for it regularly arises again, and this code, swearing, write again ... after a few hours to remove again. The fight against the first problem, as a rule, is doomed to failure. For if the code should be executed, then it should be written. And if it is written, then it scratches the eyes, breaks the main code, inflates the code, distracts and annoys. As a rule, this problem can be solved only when this code should be written at the very beginning and / or end of the function - then you can automatically generate a wrapper function that will hide this code inside.

    But you can fight the second problem quite successfully:
    warn "i=$i\n" if $DEBUG;
    In this case, performance losses when $DEBUG==0 limited to checking one scalar, i.e. in fact, the code is:
    0;

    Unfortunately, this decision leads to the fact that the “extra” code becomes even larger: if $DEBUG added to each such line. Sometimes they try to fight this by transferring this if inside the function being called:
    sub log { return if !$DEBUG; warn "$_[0]\n"; }
    log("i=$i");

    Unfortunately, the performance at the same time falls significantly stronger, because the input / output to the function is also added to the scalar check. And since the reason for the existence of $DEBUG is that performance does not fall, this method is usually not popular.

    Another option is to use the source filters technology. With its help, you can change the program code before perl starts to compile and execute it. Change like any other text, usually using regular expressions. For example, turn the code into comments, or vice versa - this will completely avoid slowing down the program (for example, see the Smart :: Comments module). The first problem with this approach is that the Perl language syntax is very complicated, and regular expressions used to modify program code (usually fairly simple) are sometimes wrong ... and it is quite difficult to find and fix such bugs. The second problem is that there is a feeling of loss of control over your code — you no longer know exactly which code is executed, because your code was somehow modified. Paradox, but the second problem completely nullifies the meaning of the existence of such modules - after all, they initially appeared to facilitate the work with the code by removing the “extra” commands from it, and as a result, working with the code, on the contrary, became more complicated.
    ')
    I want to offer you another way to solve this problem:
    BEGIN {
    *log = $ENV{DEBUG} ? sub {warn "@_"} : sub () {0};
    }
    log+ "data", 123;

    The idea is that when debugging mode is disabled, the function log is defined as a constant, and the constant functions of perl optimizes and simply substitutes their values ​​in the code instead of calling them. (The BEGIN { *log = sub () {0} } code BEGIN { *log = sub () {0} } is identical to the code use constant log => 0; ) As a result, the actual code that Perl executes will be:
    log( +"data", 123 ); # if $ENV{DEBUG}
    0 + "data", 123; # if !$ENV{DEBUG}

    As a result, we have got rid of if $DEBUG , and the function is not called when the debug mode is turned off. (And when the debugging mode is turned on - the extra unary plus can in no way spoil the first argument of the function.)

    Unfortunately, this perversion has two side effects. The first - use warnings swears at attempts to add non-numbers. The second is that this method is still a bit slower than the variant with if $DEBUG , since The arguments to the log function are evaluated even when the debug mode is disabled.

    However, despite the shortcomings, this method has the right to exist, and it may be useful to someone. In addition, I came up with it just a couple of hours ago, and perhaps it will still be possible to develop and get rid of drawbacks.

Source: https://habr.com/ru/post/17126/


All Articles