same warning multiple times when package in #ISA is not loaded - perl

while refactoring some of my perl code i
noticed the following strang behaviour.
consider this small sample script:
#!/usr/bin/perl -w
package test;
use strict;
my $obj = bless( {}, __PACKAGE__);
our #ISA = qw( missing );
exit(0)
the expected warning
Can't locate package missing for #test::ISA at test.pl line 8
appears three times instead of only one time. what are the other two triggers for this warning? all three refer to exit(0).
perl-version 5.12.4 on gentoo linux.
thanks.

I believe tjd got the answer. If you add a DESTROY() and AUTOLOAD() method to the test package, you will get only one warning (about the absence of #test::ISA).
package test;
use strict;
sub DESTROY {}
sub AUTOLOAD {}
You generally need to make sure that the packages listed in the #ISA list have already been loaded. In your example, you might have expected to see something like:
package test;
use strict;
use missing;
our #ISA = ('missing');
It is a bit curious that your package doesn't have an explicit new() method. Instead, you have a statement that calls bless();
If you had a new() method, like this:
sub new() { return bless {}, __PACKAGE__; }
Then you would not see the triple error message until something called new();
package main;
my $object = test->new(); # Triple warning
You might want to use the pragma 'base', which will give you a fatal error saying that it cannot load the 'missing' package:
package test;
use strict;
use base ('missing');
sub new { bless {}, __PACKAGE__);
The base pragma attempts to load the missing package for you. You do not need a separate 'use missing' statement.
So the final thing might look like this:
package test;
use strict;
use warning;
use base ('missing');
sub new { bless {}, __PACKAGE__);
sub DESTROY {}
sub AUTOLOAD {}
1;
You could then wrap this all into a file called test.pm and use it in a script:
use strict;
use test;
my $object = test->new(); # Should fatal, as there is no 'missing' module
Hope this helps.

Related

Why can we access the subroutine even after specifying it in EXPORT_FAIL?

Why, even after specifying subtract function in EXPORT_FAIL, am I able to access the function by defining it fully like mathematics::subtract? How can we completely make the function private?
package mathematics;
use Exporter;
#ISA = qw(Exporter);
#EXPORT = qw(add);
#EXPORT_FAIL = qw(subtract);
sub add() {
print("you can add numbers here"."\n");
}
sub subtract() {
print("you can subtract the numbers here"."\n");
}
1;
How can we completely make the function private???
You cannot. Perl doesn't have the concept of private or public.
You can however make it a lexical code reference and use that inside your code.
package Foo;
use strict;
use warnings;
my $_private = sub {
return "this is a secret";
}; # note the semicolon
sub bar {
return $_private->(); # call with reference syntax ->()
}
1;
As a lexical variable, it is now only accessible from within its scope. In this case, that scope is the file, not the package. So if you have multiple packages in one file, they can all see it. You cannot access it via a fully qualified name from outside the package.
By convention, things that should be handled as if they were private in Perl are named with a leading underscore _. That's how other developers know that something is not part of the public API of a module and that it's subject to change and should not be messed with. Of course that doesn't stop anybody from doing it, but generally there is no reason to stop them.
Also note that package names in Perl typically are written in camel case with the first letter being capitalised. Your package should be called Mathematics, and it should have use strict and use warnings.
From Perl 5.18, you can use lexical subroutines to achieve what you want. The documentation says this:
These subroutines are only visible within the block in which they are
declared, and only after that declaration:
# Include these two lines if your code is intended to run under Perl
# versions earlier than 5.26.
no warnings "experimental::lexical_subs";
use feature 'lexical_subs';
foo(); # calls the package/global subroutine
state sub foo {
foo(); # also calls the package subroutine
}
foo(); # calls "state" sub
my $ref = \&foo; # take a reference to "state" sub
my sub bar {
...
}
bar(); # calls "my" sub
p.s. Lexical subroutines are non-experimental from 5.26.

How to create globally available functions in Perl?

Is it possible to create global functions available across all namespaces like perl built-in functions?
First of all, "function" is the name given to Perl's named list operators, named unary operators and named nullary operators. They are visible everywhere because they are operators, just like ,, && and +. Subs aren't operators.
Second of all, you ask how to create a global sub, but all subs are already global (visible from everywhere) in Perl! You simply need to quality the name of the sub with the package if it's not in the current package. For example, Foo::mysub() will call my_sub found in package Foo from anywhere.
But maybe you want to be able to say mysub() instead of Foo::mysub() from everywhere, and that's a very bad idea. It violates core principles of good programming. The number of types of problems it can cause are too numerous to list.
There is a middle ground. A better solution is to create a sub that can be imported into the namespaces you want. For example, say you had the module
package Foo;
use Exporter qw( import );
our #EXPORT_OK = qw( my_sub );
our %TAGS = ( ALL => \#EXPORT_OK );
sub my_sub { ... }
1;
Then, you can use
use Foo qw( my_sub );
to load the module (if it hasn't already been loaded) and create my_sub in the current package. This allows it to call the sub as my_sub() from the package into which it was imported.
There is nothing simple that would allow one to somehow "register" user's subs with the interpreter, or some such, so that you could run them as builtins in any part of the program.
One way to get the behavior you ask for is to directly write to symbol tables of loaded modules. This has to be done after the modules have been loaded, and after subs that you add to those modules have been defined. I use INIT block in the example below.
Note that this has a number of weaknesses and just in general the idea itself is suspect to me, akin to extending the interpreter. Altogether I'd much rather write a module with all such subs and use standard approaches for good program design to have that module loaded where it needs to go.
Having said that, here is a basic demo
use warnings;
use strict;
use feature 'say';
use Data::Dump qw(dd pp);
use TestMod qw(modsub);
sub t_main { say "In t_main(), from ", __PACKAGE__ }
modsub("Calling from main::");
INIT {
no strict 'refs';
foreach my $pkg (qw(TestMod)) {
*{ $pkg . '::' . 'sub_from_main' } = \&t_main;
}
dd \%TestMod::;
}
This copies the reference to t_main from the current package (main::) into the symbol table of $pkg, under the name of sub_from_main, which can then be used with that name in that package.
For simplicity the name of the module is hardcoded, but you can use %INC instead, and whatever other clues you have, to figure out what loaded modules' stashes to add to.
The benefactor (or the victim?) module TestMod.pm
package TestMod;
use warnings;
use strict;
use feature 'say';
use Exporter qw(import);
our #EXPORT_OK = qw(modsub);
sub modsub {
say "In module ", __PACKAGE__, ", args: #_";
say "Call a sub pushed into this namespace: ";
sub_from_main();
}
1;
The name of the added sub can be passed to modules as they're loaded, instead of being hardcoded, in which case you need to write their import sub instead of borrowing the Exporter's one.
There are also modules that allow one to add keywords, but that's no light alternative.
The answer seems to be no, but you can impliment most of the behaivior that you want by using the symbol table *main::main:: to define a subroutine in all the namespaces.
use strict;
use warnings;
use Data::Dump qw(dd);
my $xx = *main::main::;
package A;
sub test {
printf "A::%s\n", &the_global;
}
package B;
sub the_global
{
"This is B::the_global";
}
sub test {
printf "B::%s\n", &the_global;
}
package main;
my $global_sub = sub { "The Global thing" };
for my $NS (keys %$xx) {
if ($NS =~ /^[A-Z]::$/) {
my $x = $NS . 'the_global';
if (defined &$x) {
printf "Skipping &%s\n", $x;
} else {
printf "Adding &%s\n", $x;
no strict 'refs';
*$x = $global_sub;
}
}
}
A::test;
This will not work on packages that are not referenced at all before the for loop above is run. But this would only happen if a require, use or package was eval'd after the code started running.
This is also still a compiler issue! You either need to refer to the global function as the_global() or &the_global if you are (as you should be) using use strict.
Sorry for my late response and thank you all for yours detailed answers and explanations.
Well.. I understood the right answer is: IT'S NOT POSSIBLE!
I'm mantaining a Perl framework used by some customers, and that framework exports some specialized subs (logging, event handling, controllers for hardware devices, domain specific subs and so). That's why I tried to figure out how to prevent the developers from importing my subs in all their packages.

Perl: Inheritance in modules - import and interfacing

I am trying to create my own module in perl that provides functions for data analysis out of a database.
I have several functions in EDL::Functions, eg. EDL::Functions::Average.
package EDL::Functions;
use warnings;
use strict;
package EDL::Functions::Average;
use parent "EDL::Functions";
sub new{...}
sub execute {...}
1) What do i have to add so use EDL::Functions; automatically imports all modules in EDL::Functions? Currently i have to import all submodules (in EDL::Functions)in order to make it work:
BEGIN {
our $VERSION = 5.20;
use EDL::Functions::Average;
use EDL::Functions::GetAllValues;
use EDL::Functions::GetValueStart;
use EDL::Functions::GetValueEnd;
use EDL::Functions::Min;
use EDL::Functions::Max;
use EDL::Functions::Median;
}
2) I want to make sure that if someone else builds his own function module the compilation will fail if it doesn't have the functions new and execute. How can i achieve that?
Thanks for your help!
It should work
perl -I ./ -MEDL::Functions -e 'EDL::Functions::Average->new();'
returns "I'm new".
cat EDL/Functions.pm
package EDL::Functions;
use warnings;
use strict;
package EDL::Functions::Average;
use parent "EDL::Functions";
sub new{ print "I'm new"; }
sub execute { print "Executing something";}
1;
But I prefere different structure, not declare several packages in one pm file. It'll save time for other devs and follows common practice, so EDL::Functions::Average should be at EDL/Functions/Average.pm

Undefined subroutine called [duplicate]

This question already has answers here:
Perl - Package/Module Issues
(4 answers)
Closed 9 years ago.
I am trying to do simple module usage in Perl:
Flame/Text.pm:
package Flame::Text;
sub words { … }
1;
Flame/Query.pm:
package Flame::Query;
use Flame::Text qw(words);
sub parse_query { words(shift); }
parse_query 'hi';
1;
Why am I getting the following error message?
Undefined subroutine &Flame::Query::words called at Flame/Query.pm line 3.
The following works just fine:
package Flame::Query;
use Flame::Text;
sub parse_query { Flame::Text::words(shift); }
parse_query 'hi';
1;
You never imported or exported the words subroutine from the Flame::Text package. A statement use Some::Module #args is equivalent to:
BEGIN {
require Some::Module;
Some::Module->import(#args);
}
that is, the import method is called with the specified arguments. This method would usually export various symbols from one package into the calling package.
Don't write your own import, rather you can inherit one from the Exporter module. This module is configured by storing exportable symbols in the #EXPORT_OK global variable. So your code would become:
package Flame::Text;
use parent 'Exporter'; # inherit from Exporter
our #EXPORT_OK = qw/words/; # list all subs which you want to export upon request
sub words { ... }
Now, use Flame::Text 'words' will work as expected.
You need to do something like this
package Flame::Text;
use Exporter 'import'; # gives you Exporter's import() method directly
#EXPORT_OK = qw(words); # symbols to export on request
as perl doesn't export (or pollute) the namespace by default
http://perldoc.perl.org/Exporter.html
don't forget to
use strict; use warnings;
in all things perl

Can't locate object method via package subclassing DBI

this is my first foray into subclassing with perl and I am wondering why I am getting this simple error...
"Can't locate object method "prepare" via package "WebDB::st" at /home/dblibs/WebDB.pm line 19.". It seems to find the module WebDB ok, but not the prepare subroutine in ::st
First here's my package (both packages are in one file, WebDB.pm)
package WebDB;
use strict;
use DBI;
sub connect {
my $dbh = (DBI->connect ("DBI:mysql:test:127.0.0.1", "root","",
{ PrintError => 1, RaiseError => 0 }));
return bless $dbh, 'WebDB::st';
}
package WebDB::st;
our #ISA = qw(::st);
sub prepare {
my ($self, $str, #args) = #_;
$self->SUPER::prepare("/* userid:$ENV{USER} */ $str", #args);
}
1;
I also tried replacing the "our #ISA = qw(;;st)" with "use base 'WebDB'" and same problem.
I'm thinking it's probably something very simple that I'm overlooking. Many thanks! Jane
Subclassing DBI has to be done just right to work correctly. Read Subclassing the DBI carefully and properly set RootClass (or explicitly call connect on your root class with #ISA set to DBI). Make sure you have WebDB::st subclassing DBI::st and a WebDB::db class subclassing DBI::db (even if there are no methods being overridden). No need to rebless.
Avoid using base; it has some unfortunate behavior that has led to its deprecation, particularly when used with classes that are not in a file of their own.
Either explicitly set #ISA or use the newer parent pragma:
package WebDB;
use parent 'DBI';
...
package WebDB::db;
use parent -norequire => 'DBI::db';
...
package WebDB::st;
use parent -norequire => 'DBI::st';
...
Are WebDB and WebDB::st in one file or two? If they are in separate files, I don't see anything that is doing a use WebDB::st;, which would cause that file to be loaded.
You can do either of these things as a remedy -- put the two packages in the same file (that would look exactly as you have pasted it above), or add a use WebDB::st; line in WebDB.pm.
(I'd also add use strict; use warnings; in both these packages too.)
Also, the prepare function is not in ::st -- there is no such package (unless it is defined elsewhere). prepare is in the WebDB::st namespace -- via the package declaration. You are however declaring that WebDB::st has ::st as a parent.
If subclassing is as tricky as ysth seems to think, I might recommend Class::Delegator from CPAN. I use if for classes that want to act like IO. And by it, Perl is the first language (that I am aware of) that has an expression language for aggregation, delegation, encapsulation almost equal with inheritance.
package WebDB;
use strict;
use DBI;
use Class::Delegator
send => [ qw<connect ...> ]
, to => '{_dbihandle}'
...
;