Re: ISA with packages ... A barebones minimal example
by ikegami (Patriarch) on Oct 08, 2004 at 15:42 UTC
|
Question 1
B::... means look in package B specifically, not B and its base classes. Use B->... to do what you want:
print B->SayBye();
Keep in mind that sends an extra argument to SayBye, and SayBye's prototype is ignored if one is specified.
Question 2
You'll need to add a 1; at the end of each .pm file, but that's it.
Question 3
Your @ISA should probably be set at compile time:
BEGIN { our @ISA = ... }
Your Exporter code won't export anything until you move the packages to seperate files (because import never gets called). It's costumary to do Exporter stuff at compile time, yet it seems to work as is as well. (Update: It said the opposite earlier, until I realized inline code is probably executed before import is called. I tested it for confirmation.) You might want to get rid of Exporter completely if you're using Module->. Also, although not a bug, it's rarely nice to use @EXPORT instead of @EXPORT_OK.
| [reply] [d/l] [select] |
Re: ISA with packages ... A barebones minimal example
by Arunbear (Prior) on Oct 08, 2004 at 15:42 UTC
|
B::SayBye() is an ordinary subroutine call and won't work because SayBye() is not in B. B->SayBye() OTOH is a method call, so Perl will look in B's super classes for SayBye().
| [reply] [d/l] [select] |
Re: ISA with packages ... A barebones minimal example
by JediWizard (Deacon) on Oct 08, 2004 at 15:46 UTC
|
Well right off the bat, there is something wrong with the code you posted. package B defines sub SayByeBye, but it Exports "SayBye". If you want package B to inherit sub SayBye from Package A, you need to use the -> operator, and probably should be using objects access the inherited methods. While the code below will work, I think you need to review why you are using Exporter, and whether you want a procedural approach, or an OO approach.
package A;
require Exporter;
our @ISA = qw/ Exporter /;
our @EXPORT = qw/ SayBye /;
our $language = "US-English";
$A::first = "Alpha";
sub SayHello {"hello from package A\n"};
sub SayBye {"Goodbye.\n"}
package B;
require Exporter;
our @ISA = qw/ Exporter A /;
our @EXPORT = qw/ SayBye /;
$B::first = "Bravo";
sub SayHello {"hello from package B\n"};
sub SayByeBye {print "\$_[0] == $_->[0]\n";$_[0]->SayBye().$_[0]
+->SayBye();}
package main;
### begin_: get stuff from A
print("$A::first\n");
print A::SayHello();
print("$language\n");
print A::SayBye();
print "\n---------------------\n";
### begin_: get stuff from B
print("$B::first\n");
print B::SayHello();
print("$language\n");
print B->SayBye(); ### <-- ERROR Undefined subroutine &B::SayB
+ye
print B->SayByeBye();
print "\n---------------------\n";
May the Force be with you
| [reply] [d/l] [select] |
Re: ISA with packages ... A barebones minimal example
by jeffa (Bishop) on Oct 08, 2004 at 16:39 UTC
|
I am responding to your title, not your questions. If you want a barebones minimal example, drop the export. As JediWizard suggested, use OO, not function exporting. If you want a method, you need an object first.
#!/usr/bin/perl -l
package main;
for (Dog->new, Cat->new, Cow->new, Foo->new) {
print "Oh the ", $_->name, " goes ", $_->speak;
}
package Animal;
sub new { bless {}, shift }
sub speak { return "ERROR: did not override" }
sub name { return ref shift }
package Dog;
use base 'Animal';
sub speak { return "Woof" }
package Cat;
use base 'Animal';
sub speak { return "Meow" }
package Cow;
use base 'Animal';
sub speak { return "Moo" }
package Foo;
use base 'Animal';
Take a look at base ... use it instead of munging @INC directly, unless you
absolutely have to.
| [reply] [d/l] |
Re: ISA with packages ... A barebones minimal example
by ambrus (Abbot) on Oct 08, 2004 at 16:27 UTC
|
| [reply] [d/l] |
|
|
I have to agree with ambrus here, though he was a bit brief...
We've had nodes here about bugs in people's code, where things didn't work as expected, and the cause was the use of "A", "B", and "C" as the package names (I might actually try to locate one, soonish). The cause is B comes with perl, and is the root to a module suite, to compile/decompile perl scripts. When I say B::Deparse the lightbulb might just flash to on.
Just don't use "A", "B" etc. You could try "Alpha", "Beta" instead, or maybe even "Foo", "Bar".
| [reply] |
Re: ISA with packages ... A barebones minimal example
by radiantmatrix (Parson) on Oct 08, 2004 at 17:33 UTC
|
You appear to be confusing package references with objects. Perl is not solely object-oriented, like Java or other langauages.
The B::method syntax is a package reference. It looks for a method inside package B. Adding a method to @EXPORT allows you to use that method without referencing the package directly.
What you are looking for is object inheritance. Objects don't need to be exported. You reference an object inside package B with B->object. If that object is a subroutine, it will be called (with parameters).
That's why everyone is saying "use B->". Your inclusion of A in @ISA causes B to inherit A's objects, but not package references. Do you understand?
radiantmatrix
require General::Disclaimer;
| [reply] |
|
|
The B::method syntax is a package reference. It looks for a method inside package B.
No, it looks for a subroutine inside package B. A subroutine is not a method unless it is called with the pointy arrow syntax. This may be slightly confusing, but it's important to pay attention to the difference, because methods and normal subroutine calls receive different arguments.
B::foo; # subroutine call
B->foo; # method call
| [reply] [d/l] |
|
|
Sorry, I forgot that OO-language CS types use "method" to mean exclusively object methods. I generally use the term as a generic way of saying "subroutine, function, procedure, accessor, etc.". So, using my nomenclature:
B::bar; #package method (subroutine, in this case)
B->bar; #object method (subroutine, in this case)
Hope that clears up any vaguities in my earlier post.
radiantmatrix
require General::Disclaimer;
| [reply] [d/l] |
|
|
| [reply] |
The Scope Resolution Operator (was Re: ISA with packages ... A barebones minimal example)
by Anonymous Monk on Oct 08, 2004 at 18:36 UTC
|
Thanks to the responses and a little digging, I know now enough to re-ask the original question. The real sticking point was this ... "what are the available alternatives to the standard scope resolution operator in perl (aka double-colon)".
Although the suggestions about using OO programming are appreciated, the problem is I have two pre-existing packages "Alpha" and "Bravo" (lets avoid the names A and B) and they are already done and not coded OO-style, they're just filled with run-of the mill subroutines.
With that in mind, I redid the barebones example, I took out all the Exporter stuff, and just used @ISA in tandem with Bravo->SayBye() ... it worked as expected.
The new problem is, that Bravo->SayBye() does not exactly work the same as Bravo::SayBye() because the first one (invisibly?) passes an extra argument, as someone already pointed out. That's not good because it messes up the expected results of the subroutines.
What it all boils down to is I need to do inheritance but without being able to rewrite "OO style" package code, and without the benefit of having the double-colon scope resolution operator as an option. That's essentially what I was trying to do. Any more suggestions? Do I have to go in and rewrite Alpha and Bravo just to be able to do inheritance?
| [reply] |
|
|
Here is one way to 'inherit' subroutines without rewriting your packages in the OO style:
use strict;
use warnings;
package Alpha;
our $language = "US-English";
$Alpha::first = "Alpha";
sub SayHello {"hello from package Alpha\n"};
sub SayBye {"Goodbye.\n"}
sub GreetByName {"Well Hello $_[0].\n";}
package Bravo;
our $AUTOLOAD;
sub AUTOLOAD {
$AUTOLOAD =~ s/^.+:://; # strip package name
*sym = $Alpha::{$AUTOLOAD};
*sym{CODE}->(@_);
}
$Bravo::first = "Bravo";
sub SayHello {"hello from package Bravo\n"};
package main;
### begin_: get stuff from A
print("$Alpha::first\n");
print Alpha::SayHello();
print("$language\n");
print Alpha::SayBye(); # -> Goodbye.
print Alpha::GreetByName('Dolly'); # -> Well Hello Dolly.
print "\n---------------------\n";
### begin_: get stuff from Bravo
print("$Bravo::first\n");
print Bravo::SayHello();
print("$language\n");
print Bravo::SayBye(); # -> Goodbye.
print Bravo::GreetByName('Billy'); # -> Well Hello Billy.
print "\n---------------------\n";
Here, when you call Bravo::foo() but foo() is not in Bravo, Bravo's AUTOLOAD subroutine will call Alpha's foo() subroutine. See 'Autoloading' in perlsub for more on AUTOLOAD.
| [reply] [d/l] |
reworked code but still doesnt work ...
by Anonymous Monk on Oct 08, 2004 at 18:47 UTC
|
use strict;
package Alpha;
our $language = "US-English";
$Alpha::first = "Alpha";
sub SayHello {"hello from package Alpha\n"};
sub SayBye {"Goodbye.\n"}
sub GreetByName {"Well Hello $_[0].\n";}
package Bravo;
our @ISA = qw(Alpha);
$Bravo::first = "Bravo";
sub SayHello {"hello from package Bravo\n"};
package main;
### begin_: get stuff from A
print("$Alpha::first\n");
print Alpha::SayHello();
print("$language\n");
print Alpha::SayBye();
print Alpha::GreetByName('Dolly'); ### works as expected
print Alpha->GreetByName('Dolly'); ### D'OH! not what we expected
print "\n---------------------\n";
### begin_: get stuff from Bravo
print("$Bravo::first\n");
print Bravo::SayHello();
print("$language\n");
print Bravo->SayBye(); ### works as expected
print Bravo->GreetByName('Billy'); ### D'OH! 'Hello Bravo'
print "\n---------------------\n";
1;
__END__
| [reply] [d/l] |
|
|
I'll just pick one example, because the other one works the same, only without inheritance.
print Bravo->SayBye(); ### works as expected
print Bravo->GreetByName('Billy'); ### D'OH! 'Hello Bravo'
The syntax Package->subname(@arguments) calls a class method, with inheritance if needed. The first argument supplied to the sub subname will be the name of the Package, in your case, @_ = ("Bravo","Billy"). Likewise, for methodcalls on objects, the object is passed as the first argument. Some languagages prefer to do this behind your back (i.e. Java & C++'s this object), but Perl is very explicit about all of this.
In your code, you don't need that first argument, so just ignore it, however, if you want to bless objects into the right class, or pass the package name on, you do need it.
See also perltoot perlobj,perlobj, perlboot, perltooc, and perlbot.
| [reply] [d/l] [select] |