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

Hi, I'm looking to do something like this:
Package GlobalDefined; use strict; use warnings; our $PROJECT_GLOBAL_VAR1; ... # Tools use Data::Dumper; ... 1;
Now, I'd like to add some kind of use/require so that the definitions that I include in global defines are taken in other packages/scripts. That means not only the global variables (which is easy) but also things like ' use strict ' or ' use Data::Dumper ' . To me, it feels like writing a central "include <> /Macro / define" file in C++. Is this possible in Perl ? Appreciate the answers !

Replies are listed 'Best First'.
Re: Code Reuse
by LanX (Saint) on Aug 20, 2017 at 17:58 UTC
    A use is basically a require plus a call to the import sub of the included package.

    And import is executed in the context of the calling package.

    Thus you can call other imports inside a generic import to export into the calling namespace.

    For instance:

    package generic; use strict; # * ... sub import { strict->import(); ... }

    You might wanna have a look into the source of Modern::Perl for more examples.

    Cheers Rolf
    (addicted to the Perl Programming Language and ☆☆☆☆ :)
    Je suis Charlie!

    Update

    *) Had to change require strict; to use strict; to make it work. (not sure why)

    Answer

    It's a timing issue, the require has to happen in a BEGIN or inside the import (use does it automatically), this works

    package generic; sub import { require strict; strict->import(); ... } 1;
Re: Code Reuse
by poj (Abbot) on Aug 20, 2017 at 17:03 UTC
Re: Code Reuse
by Athanasius (Archbishop) on Aug 21, 2017 at 06:08 UTC

    Hello Mano_Man,

    Looking through the various options in the thread linked by poj, the simplest/cleanest looks to be Syntax::Collector by tobyink. Here’s an example:

    File GlobalDefined.pm:

    package GlobalDefined; our $VERSION = 1; our $PROJECT_GLOBAL_VAR1 = 42; use Syntax::Collector q{ use strict 0; use warnings 0; use Data::Dumper 2.161; use Data::Dump 1.23 qw( pp ); }; 1;

    File main.pl:

    package GlobalDefined; use GlobalDefined; our $PROJECT_GLOBAL_VAR1; print 'My global = >', pp($PROJECT_GLOBAL_VAR1), "<\n";

    Note that you still have to do a bit of work to access package globals in the calling script. This is probably a good thing, as globals should be used as sparingly as possible. (In my experimenting, I couldn’t get Exporter to play nicely with either Syntax::Collector or ToolSet when exporting package variables.)

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Code Reuse
by shmem (Chancellor) on Aug 20, 2017 at 17:04 UTC

    See Exporter. Via the same semantics you can export any symbols imported from other packages into this packages caller.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
Re: Code Reuse
by stevieb (Canon) on Aug 20, 2017 at 20:12 UTC

    This follow up is just an example, and to be honest, I've put it here for thoroughness... it'll break in many cases, so don't use it.

    You can exploit the symbol table to slurp in subs from modules that have imported them into their own namespaces. Know that "namespaces" are important in Perl (and in any other language that deals with them) due to logical (ie. lexical) scoping. The following will show how to check a 'use'd module for subs itself has, and import them all into the current namespace. Again, this is bound to break (I haven't even considered ramifications on included modules that use OO, and not using strict in the way I have here could be catastrophic (if it isn't already ;) ).

    Rephrasing... it'll import *all* subroutines that's in the module's namespace as it currently sits, which is almost certainly not what you want. Look at it as indiscriminate inclusion.

    First, the all-inclusive module you want to pull from (X.pm):

    package X; use Data::Dumper; use File::Copy qw(copy); use Time::HiRes qw(usleep); 1;

    Now, the x.pl script that wants everything from the module:

    use warnings; use strict; use lib '.'; use X; BEGIN { no strict 'refs'; for (keys %X::){ my $symbol = "X::$_"; if (defined &{$symbol}){ print "importing '$symbol' sub into our namespace\n"; *$_ = \&{$symbol}; } } } print Dumper {a => 1}; usleep 500000; copy 'x.txt', 'y.txt' or die $!;

    Output:

    importing 'X::copy' sub into our own namespace importing 'X::usleep' sub into our own namespace importing 'X::Dumper' sub into our own namespace $VAR1 = { 'a' => 1 }; No such file or directory at x.pl line 20.

    Please don't do this unless you know exactly why you're doing it, what you're doing it for, and with knowledge exactly why you want to 'cheat'. The other Monks have put forth much better examples of how to accomplish what you really want in much more eloquent ways.

    This could be relatively trivially adapted so that the module itself saturates the caller script's namespace with the subs, but because this is not a recommended technique unless required for very specific purposes, I'll leave it up to the reader to figure that piece out.

Re: Code Reuse
by Anonymous Monk on Aug 21, 2017 at 16:10 UTC
    What you're trying to do is actually the opposite of code reuse. "But I'm reusing all these use statements!" No, you're creating unnecessary dependencies between your modules, which makes it that much harder to take one of those modules and use it in a different project. Code reuse is actually quite difficult to do right.
Re: Code Reuse
by Mano_Man (Acolyte) on Aug 28, 2017 at 14:17 UTC

    I've read the comments here, and the comments in the attached post regarding the same.

    My conclusion is this: There is no comfortable and/or smart way to this as opposed to C++. Some code might be saved, but it is simply not entirely feasible.

    My requirements were:

    * Shared 'use' statements in the file scope

    * Shared 'our' variables in the file scope

    * Shared 'libs' in the file scope

    + A system that checks the possibility of a connectivity fault in one of the packages.

    How smart/code-wise/good habit this request is a matter of taste and not relevant in my beliefs.

      You got very good answers for a not very well formulated question, partly also because most of us are not C++ users.

      What for instance is "connectivity fault" supposed to mean? see How do I post a question effectively?

      But if you thing C++ is better, go on use it ...

      Probably we should lead you to Source-Filters and let you have fun there, like Filter::Include, instead suggesting more stable approaches?

      EDIT

      and please note that you can easily compile your own Perl version with C like pre-processor support

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!