'Subroutine redefined' annoyance

B

bill

If I uncomment the 'use SlicesDices ...' line below, running the
script/module from the command line results in a 'Subroutine quux
redefined' warning.

#!/usr/bin/perl -w use strict;
# SlicesDices.pm

package SlicesDices;
use base 'Exporter';

BEGIN { push @SlicesDices::EXPORT, 'quux' }
sub quux {
local $| = 1;
print "hello from quux\n";
return;
}

return 1 if (caller(0))[7];

package main;

# use SlicesDices; # results in a 'redefined' warning
# quux();

__END__


The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?

Thanks!

bill
 
P

Paul Lalli

bill said:
If I uncomment the 'use SlicesDices ...' line below, running the
script/module from the command line results in a 'Subroutine quux
redefined' warning.

#!/usr/bin/perl -w use strict;
# SlicesDices.pm

package SlicesDices;
use base 'Exporter';

BEGIN { push @SlicesDices::EXPORT, 'quux' }
sub quux {
local $| = 1;
print "hello from quux\n";
return;
}

return 1 if (caller(0))[7];

package main;

# use SlicesDices; # results in a 'redefined' warning
# quux();

__END__

The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?

use does a require before the import. You have no reason to do a
require, because the code for both packages is in the same file.
Replace 'use SlicesDices;' with 'import SlicesDices;'

Paul Lalli
 
A

Anno Siegel

bill said:
If I uncomment the 'use SlicesDices ...' line below, running the
script/module from the command line results in a 'Subroutine quux
redefined' warning.

#!/usr/bin/perl -w use strict;
# SlicesDices.pm

package SlicesDices;
use base 'Exporter';

BEGIN { push @SlicesDices::EXPORT, 'quux' }
sub quux {
local $| = 1;
print "hello from quux\n";
return;
}

return 1 if (caller(0))[7];

package main;

# use SlicesDices; # results in a 'redefined' warning
# quux();

__END__
The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?

You're mixing two techniques. Either you have the module code in an
extra *.pm file, then you "use" it. Or you make the module code part
of the client code. Then you don't use it. In the simplest case,
when they are meant to stay together, you can just informally import
things:

*quux = \ &SlicesDices::quux;

That's exactly what Exporter does, the reset is bells and whistles you
don't really need in a single source file.

If you want to simulate "use SlicesDices arg1 arg2" exactly, replace
the use statement with two BEGIN blocks. The first one contains the
module code exactly as it would appear in an external file. The second
one calls the modules ->import method with the intended arguments:

BEGIN {
SlicesDices->import( arg1, arg2);
}

That's the basic recipe.

Anno
 
A

Anno Siegel

bill said:
If I uncomment the 'use SlicesDices ...' line below, running the
script/module from the command line results in a 'Subroutine quux
redefined' warning.

#!/usr/bin/perl -w use strict;
# SlicesDices.pm

package SlicesDices;
use base 'Exporter';

BEGIN { push @SlicesDices::EXPORT, 'quux' }
sub quux {
local $| = 1;
print "hello from quux\n";
return;
}

return 1 if (caller(0))[7];

package main;

# use SlicesDices; # results in a 'redefined' warning
# quux();

__END__
The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?

You're mixing two techniques. Either you have the module code in an
extra *.pm file, then you "use" it. Or you make the module code part
of the client code. Then you don't use it. In the simplest case,
when they are meant to stay together, you can just informally import
things:

*quux = \ &SlicesDices::quux;

That's exactly what Exporter does, the rest is bells and whistles you
don't really need in a single source file.

If you want to simulate "use SlicesDices arg1 arg2" exactly, replace
the use statement with two BEGIN blocks. The first one contains the
module code exactly as it would appear in an external file. The second
one calls the modules ->import method with the intended arguments:

BEGIN {
SlicesDices->import( arg1, arg2);
}

That's the basic recipe.

Anno
 
B

bill

In said:
bill said:
If I uncomment the 'use SlicesDices ...' line below, running the
script/module from the command line results in a 'Subroutine quux
redefined' warning.

#!/usr/bin/perl -w use strict;
# SlicesDices.pm

package SlicesDices;
use base 'Exporter';

BEGIN { push @SlicesDices::EXPORT, 'quux' }
sub quux {
local $| = 1;
print "hello from quux\n";
return;
}

return 1 if (caller(0))[7];

package main;

# use SlicesDices; # results in a 'redefined' warning
# quux();

__END__
The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?
You're mixing two techniques. Either you have the module code in an
extra *.pm file, then you "use" it. Or you make the module code part
of the client code. Then you don't use it.

Yes, I realize that I'm mixing techniques here. I'm trying to find
a satisfactory solution to a recurrent situation: I write a Perl
script to be used from the command line, but soon enough I discover
that I want the script's functionality from within another script.
I don't want to rely on system calls to do this. I also don't like
the fuss of splitting the original script into a "module file" and
a "wrapper file".

Hence I thought I'd write the original script as a subclass of
Exporter in the first place, and stick it in a a file foo.pm along
with extra code in main to take care of the command-line functionality
(including options parsing and checking, help screens, and whatever
else the command-line script would need to do that the module
wouldn't have to worry about). I put this foo.pm file in a directory
in @INC, make it executable, and put a suitable symbolic link foo
to it in a directory in my $PATH. In this way I can call the script
from the command line, or "use" it from another script.

If there's a better way that meet all my neurotic criteria, I'd
love to hear it.

bill
 
B

bill

In said:
bill said:
If I uncomment the 'use SlicesDices ...' line below, running the
script/module from the command line results in a 'Subroutine quux
redefined' warning.

#!/usr/bin/perl -w use strict;
# SlicesDices.pm

package SlicesDices;
use base 'Exporter';

BEGIN { push @SlicesDices::EXPORT, 'quux' }
sub quux {
local $| = 1;
print "hello from quux\n";
return;
}

return 1 if (caller(0))[7];

package main;

# use SlicesDices; # results in a 'redefined' warning
# quux();

__END__

The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?
use does a require before the import. You have no reason to do a
require, because the code for both packages is in the same file.
Replace 'use SlicesDices;' with 'import SlicesDices;'

Worked like a charm. Thanks!

bill
 
X

xhoster

bill said:
The problem seems to be that the 'use SlicesDices' statement is
causing the file to be read again. Is there any reasonably scalable
way to import the subs in @SlicesDices::EXPORT to the main namespace
without using "use", and not causing the redefinition to take place?

Out of curiousity, what do mean by scalable in this context?

Xho
 
B

bill

Out of curiousity, what do mean by scalable in this context?

Bad wording on my part. I just wanted to rule out strategies
involving a bazillion assignments a la:

*quux = \&SlicesDices::quux;
*foo = \&SlicesDices::foo;
*bar = \&SlicesDices::bar;
....
*baz = \&SlicesDices::baz;

bill
 
A

Anno Siegel

bill said:
In <[email protected]>
(e-mail address removed)-berlin.de (Anno Siegel) writes:
[...]

to it in a directory in my $PATH. In this way I can call the script
from the command line, or "use" it from another script.

If there's a better way that meet all my neurotic criteria, I'd
love to hear it.

A module doing double-time as a script? Besides the obvious shebang line,
check caller() to see if you want to execute the "script code" (untested):

if ( caller ) {
OddsAndEnds->import(); # parameters as needed
require Getopt::STD; # for instance
# more script code here
}

package OddsAndEnds;
BEGIN {
our @ISA = qw( Exporter);
# other initialization of module
}
# etc...

The script part will only execute when it is called from the command
line, not if use'd or require'd (see perldoc -f caller). If so, it
will jump through your module's import hoops. Stuff that only the
script needs should be require'd, not use'd. Since imports in the
script happen at run time, you'll have to use parens with imported
functions, but that's the only restriction I see.

If you want the script first and the module later (I prefer it that way)
you'll have to put module initialization code in a BEGIN block as
indicated.

Anno
 
B

bill

In said:
bill said:
In <[email protected]>
(e-mail address removed)-berlin.de (Anno Siegel) writes:
to it in a directory in my $PATH. In this way I can call the script
from the command line, or "use" it from another script.

If there's a better way that meet all my neurotic criteria, I'd
love to hear it.
A module doing double-time as a script?

Yeah. It's pretty common in the Python world, although the use
I've typically seen for the "executable script code" in Python
modules is devoted to tests of the module.

Frankly, I'm surprised it is not more common to see Perl modules
that do double-duty as scripts. It happens to me all the time that
I want to use some functionality that I implemented earlier in some
script. I find the "standard" way to handle such situations (namely,
re-factor the original script into module and wrapper script files,
which will most likely reside in separate directories) artificial
somehow. It makes a lot more sense to me to keep everything in
one file, and make the script's desired functionality exportable.
Besides the obvious shebang line,
check caller() to see if you want to execute the "script code" (untested):
if ( caller ) {
OddsAndEnds->import(); # parameters as needed
require Getopt::STD; # for instance
# more script code here
}

I assume you meant "unless ( caller )"?
Stuff that only the
script needs should be require'd, not use'd. Since imports in the
script happen at run time...

You'd also need explicit import statements, no? (Or use
package-qualified subs?)
If you want the script first and the module later (I prefer it that way)

Just out of curiosity, is that preference a matter of aesthetics
alone, or is there a functional rationale for putting the script
before? (I think my preference was shaped by all the Python scripts
I've seen with the "script code" at the end.)

bill
 
A

Anno Siegel

bill said:
In <[email protected]>
[...]
A module doing double-time as a script?

Yeah. It's pretty common in the Python world, although the use
I've typically seen for the "executable script code" in Python
modules is devoted to tests of the module.

Frankly, I'm surprised it is not more common to see Perl modules
that do double-duty as scripts. It happens to me all the time that

Ready-to-run scripts aren't much distributed at all in the Perl world.
One alternative is for the module to offer a shell that is exported
by default. CPAN is an example, but there are others. An interactive
session is started through "perl -MCPAN -e shell". OTOH command-line
callable modules aren't unknown, my own Vi::QuickFix is an example.
I assume you meant "unless ( caller )"?

Yes, of course. Sorry.
You'd also need explicit import statements, no? (Or use
package-qualified subs?)

I have written an import statement, but you can also compile the script in
the module package (just put the package-statement above the script).
If it is an exporting module, the script should probably call ->import,
if only for a crude test.
Just out of curiosity, is that preference a matter of aesthetics
alone, or is there a functional rationale for putting the script
before? (I think my preference was shaped by all the Python scripts
I've seen with the "script code" at the end.)

The arrangement (script first, module later) has no functional advantage,
even a bit to the contrary.

I like to maintain a top-down direction in a source. As a general rule,
that means writing first the calls to subs, then the definition of subs.
Ultimately, directly executable code goes first, hence the positioning
of the script. Compilers like it the other way 'round and Perl punishes
you by forcing you to use parens with your sub calls, and problems with
prototypes and whatnot. It's not an immutable rule.

The other way 'round you get a source that begins with the most low-level
auxiliaries until you get to see how they fit together. I find that less
convenient. I realize that "my" way, what you get to read first is parameter
passing and checking, but it does come to the point faster :)

Anno
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top