1

If I want to write code that optionally uses a module how can I do it? For example, if I want to write code that warns Dumping an object if Data::Dumper is available or otherwise just warns, how can I do that?

Evan Carroll
  • 78,363
  • 46
  • 261
  • 468
  • This question should not have been closed as a duplicate because there are two parts to the question. 1. How to optionally load a module and 2. How to optionally use a subroutine. – lordadmira Nov 20 '20 at 02:26
  • The answer to #2 is this. `use constant haveDumper => defined &Dumper; sub warning { haveDumper ? warn(Dumper @_) : warn(@_); }` The general way to check for a subroutine being available is `defined &NAME`. This matters because subroutines could be supplied by various modules. If you need to check for a subroutine that is autoloaded, use `exists &NAME`. – lordadmira Nov 20 '20 at 02:32

2 Answers2

4
BEGIN {
   if (eval { require Data::Dumper }) {
      *dumper = sub { warn(Data::Dumper::Dumper(@_)) };
   } else {
      *dumper = sub { };
   }
}

dumper(...);

The downside of the above is that expensive expressions passed as arguments still need to be calculated if Data::Dumper isn't available.

use constant has_dumper => eval { require Data::Dumper };

BEGIN {
   if (has_dump) {
      *dumper = sub { warn(Data::Dumper::Dumper(@_)) };
   } else {
      *dumper = sub { };
   }
}

dumper(...);                # Ok
dumper(...) if has_dumper;  # Statement completely optimized away if DD missing.
ikegami
  • 367,544
  • 15
  • 269
  • 518
2

This is an effective idiom for loading an optional module,

use constant has_Module => defined eval { require Module };

This will require the module if available, and store the status in a constant.

You can use this like,

use constant has_DataDumper => defined eval { require Data::Dumper };

warn "got object";
if ( has_DataDumper ) {
  warn Data::Dumper::Dumper( $obj );
}
Evan Carroll
  • 78,363
  • 46
  • 261
  • 468