0

Having a C background, I may be trying to write something the wrong way so excuse the beginner question. Here is what I'm looking for :

I'm willing to have a perl module Verbose (not a class) that define a subroutine called verbose_print(). This subroutine will print its argument (a string) only if module's variable $verbose is true. Of course, what I'm willing to do is to get the -V option from the command line (using Getopt::Long) and then, is the -V switch is on, call the Verbose module with 'true' being the value for $Verbose::verbose.

One workaround is to have a verbose_init function that set the $Verbose::verbose variable to true inside the Verbose module.

Another one was to declare $verbose in my module using our and then $Verbose::verbose = $command_line_verbose_switch in the main script.

I was wondering if there is another way to do this in perl?

bobbogo
  • 14,989
  • 3
  • 48
  • 57
claf
  • 9,043
  • 17
  • 62
  • 79
  • Questions asking "is there another way" are kind of a bad fit for SO's format, because they don't present a problem to solve and have myriad equally-valid answers. If you have some dissatisfaction with your current answers, you should specify this and ask how to overcome it. – darch Nov 04 '12 at 18:14
  • @darch the final question is indeed "is there another way" but the title implies what I'm looking for ... – claf Nov 04 '12 at 18:47

2 Answers2

1

Don't be so afraid of classes in Perl, they're just packages and modules treated a wee bit differently. They don't bite. However, you said no classes, so no classes.

I prefer not to touch package variables directly. Instead, I'll use a subroutine to set them.

Here's my Local::Verbose (stored under Local/Verbose.pm)

package Local::Verbose;

use strict;
use warnings;
use Exporter 'import';

# Could have used just '@EXPORT', but that's bad manners
our @EXPORT_OK = qw(verbose verbose_switch);

# Use "our", so $verbose_value is a package variable.
# This makes it survive between calls to this package

our $verbose_value;

# prints out message, but only if $verbose_value is set to non-blank/zero value
sub verbose {
    my $message = shift;

    if ( $verbose_value ) {
        print "VERBOSE: $message\n";
        return $message;
    }
    else {
        return;
    }
}

sub verbose_switch  {
    my $switch_value = shift;
    $verbose_value = $switch_value;
    return $switch_value;
}
1;

Notice the our. That makes $verbose_value a package variable which means it lives on outside of the package between calls.

Notice how I use Exporter and the @EXPORT_OK array. You can use @EXPORT which will export all of the named subroutines automatically, but it's now considered bad manners since you could end up covering over someone's local subroutine with the same name. Better make it explicit. If there's a problem, they can use the Local::Verbose::verbose name of the verbose subroutine.

And how it's used

use strict;
use warnings;

use Local::Verbose qw(verbose verbose_switch);

verbose ("This is a test");

verbose_switch(1);

verbose ("This is a second test");

By the way, imagine calling the verbose subroutine like this:

 verbose($message, $my_verbose_level);

Now, your verbose subroutine could look like this:

    sub verbose {
    my $message =       shift;
    my $verbose_level = shift;

    if (not defined $verbose) {
       $verbose_level = 1;
    }

    if ( $verbose_value =< $verbose_level ) {
        print "VERBOSE: $message\n";
        return $message;
    }
    else {
        return;
    }
}

Now, you can set your verbose level to various values, and have your verbose statements give you different levels of verbosity. (I do the same thing, but call it debug).

David W.
  • 105,218
  • 39
  • 216
  • 337
  • I like the improved version of `verbose ($message, $level)`. Currently I'm using almost the same code as the first version you propose, but I don't use `our` keyword, using `my $verbose_value` seems to work between package calls, what am I missing?! – claf Nov 04 '12 at 17:00
  • @darch could you please be more specific in this case? not very constructive comment ... you may for example explain the differences between the use of `my` and `our` in this specific case? – claf Nov 04 '12 at 18:46
  • 1
    @claferri Package variable swith `our` can always be accessed with a fully qualified name `$Local::Verbose::verbose_value` and thus never go out of scope. This is not the case with lexical `my` variables. However, the subs `verbose` and `verbose_switch` would be *closures* over a lexical `$verbose_value` variable. Therefore, the subs can access this variable even if the package scope is left. In this particular case, there is no real difference. Closures are essential to functional programming, but Perl is multi-paradigm so you can ignore FP if you want. – amon Nov 04 '12 at 20:01
  • @amon You're correct about direct access to the package variable. However, there are many advantages about wrapping it in a function: First, I can verify the value is correct. Second, gives me the ability to add functionality and modify my program. Let's say I made a modification, so you can pass one or two values to `verbose_switch`. Pass one, and it does what it currently does. Pass two, and something new and magical happens. Easy to do with a subroutine. Hard to do with direct access to the package variable. – David W. Nov 05 '12 at 02:16
-3

One of 'another ways' is create an import function:

package Verbose;
my $verbose_on;
sub import {
    $verbose_on = shift;
}
#... Your code.

Now you can set your verbose like this:

if( ... ) { #check getopt
    use Verbose (1); #This will require package Verbose and call "import"
}

But, i think more simple and obivious to further use is make a function-setter.

Galimov Albert
  • 7,269
  • 1
  • 24
  • 50
  • 1
    Won't that use conflict with the Exporter module ? – claf Nov 04 '12 at 14:48
  • Yes, will conflict.. But you said nothing about it=) In this case i'd prefer to do it with `verbose_init` variant and not using dirty hacks.. – Galimov Albert Nov 04 '12 at 14:50
  • Ok so redefining this import function is a dirty hack I guess :), I'll probably go with the verbose_init too as I intend to use Exporter. – claf Nov 04 '12 at 14:51
  • 3
    This is completely wrong. The `use Verbose (1)` would be executed within an implicit `BEGIN` block and therefore independent of the `if` statement. – Borodin Nov 04 '12 at 15:50
  • @Borodin ok so maybe `require`would fit the need? or would you go with the `verbose_init` function too? – claf Nov 04 '12 at 16:06