views:

242

answers:

3

I have a base class like this:

package MyClass;

use vars qw/$ME list of vars/;
use Exporter;
@ISA = qw/Exporter/;
@EXPORT_OK = qw/ many variables & functions/;
%EXPORT_TAGS = (all => \@EXPORT_OK );

sub my_method {

}
sub other_methods etc {

}

--- more code---

I want to subclass MyClass, but only for one method.

package MySubclass;

use MyClass;
use vars qw/@ISA/;
@ISA = 'MyClass';

sub my_method {

--- new method

}

And I want to call this MySubclass like I would the original MyClass, and still have access to all of the variables and functions from Exporter. However I am having problems getting the Exporter variables from the original class, MyClass, to export correctly. Do I need to run Exporter again inside the subclass? That seems redundant and unclear.

Example file:

#!/usr/bin/perl

use MySubclass qw/$ME/;

-- rest of code

But I get compile errors when I try to import the $ME variable. Any suggestions?

+5  A: 

You should access everything through methods. Forget about passing variables around.

You're getting a syntax error because you have a syntax error:

 use MySubclass /$ME/; # syntax error - that's the match operator

You want a list there:

 use MySubclass qw/$ME/;

However, don't do that. Provide access to these data through methods. Since you'll inherit the methods, you don't need (and shouldn't use) Exporter:

 package MyClass;

 BEGIN {
 my $ME;
 sub get_me { $ME }
 sub set_me { $ME = shift }
 }

Now your subclass is just:

 package MySubclass;
 use parent( MyClass );
 sub my_method { ... }

There are various modules that can automatically handle the accessor details for you if you have many variables you need to share.

brian d foy
I just forgot to include the "qw" when I wrote my example. I realize that I can export any variable through a method, but I would hope there would be a way to export ALL of my variables without creating a method for each of them. If I call "use MyClass qw/:all/;" I can access ALL of my variables. I want it to work the same way but with "use MySubclass qw/:all/;"
Jonathan
Well, go back and fix your question then. Don't type out new code. Show us the real code.
brian d foy
The real code is way to complicated and tedious to post. I only posted what is necessary to my question.
Jonathan
@Jonathan: The code you think is relevant to your question and the code that is *actually* relevant to your question are often disjoint sets. http://www.shadowcat.co.uk/blog/matt-s-trout/show-us-the-whole-code/
Dave Sherohman
Dave - understandable, but my question was not about a particular error message, it was about how to accomplish something with perl... I was just using my code as an example on what i'm trying to accomplish.
Jonathan
Always come up with a minimal but complete demonstration of your problem. You still haven't fixed your question to remove your accidental syntax error though.
brian d foy
I'm new to this website and did not realize that I could edit the original question, it is fixed now.
Jonathan
That's why I told you that you could. :)
brian d foy
+4  A: 

You're not actually inheriting MySubclass from MyClass at all -- MySubClass is a user of MyClass. What you're doing is overriding a bit of behaviour from MyClass, but you will only confuse yourself if you think of this as inheritance, because it isn't (for example: where is your constructor?) I couldn't figure out what you were trying to do until I ignored everything the code was doing and just read your description of what you want to have happen.

Okay, so you have a class which imports some symbols - some functions, and some variables:

package MyClass;
use strict;
use warnings;

use Exporter 'import';    # gives you Exporter's import() method directly
our @EXPORT_OK = qw/ many variables & functions/;
our %EXPORT_TAGS = (all => \@EXPORT_OK );
our ($ME, $list, $of, $vars);

sub my_func {

}
sub other_func {

}
1;

and then you come along and write a class which imports everything from MyClass, imports it all back out again, but swaps out one function for another one:

package MyBetterclass;
use strict;
use warnings;
use Exporter 'import';    # gives you Exporter's import() method directly
our @EXPORT_OK = qw/ many variables & functions /;
our %EXPORT_TAGS = (all => \@EXPORT_OK );
use MyClass ':all';

sub my_func {
    # new definition   
}
1;

That's it! Note that I enabled strict checking and warnings, and changed the names of the "methods" that are actually functions. Additionally, I did not use use vars (the documentation says it's obsolete, so that's a big red flag if you still want to use it without understanding its mechanics).

Ether
The code you've typed prints out a lot of error messages and dies: $ ./ether-test.pl Global symbol "@EXPORT_OK" requires explicit package name at EtherBetterClass.pm line 5.Global symbol "%EXPORT_TAGS" requires explicit package name at EtherBetterClass.pm line 6.Global symbol "@EXPORT_OK" requires explicit package name at EtherBetterClass.pm line 6.BEGIN not safe after errors--compilation aborted at EtherBetterClass.pm line 7.Compilation failed in require at ./ether-test.pl line 4.BEGIN failed--compilation aborted at ./ether-test.pl line 4.
Kinopiko
BTW that isn't my downvote.
Kinopiko
So bascially the answer is that I have to import all of my variables and then export then out again using Exporter. There is evidently no way to automatically do this? Right? I use "use vars" instead of "our" because I plan on distributing my script to people that may or may not be using the latest version of perl 5.
Jonathan
Kinopiko - you received that error because the variables must be declared, again, I use "use vars qw(@EXPORT_OK %EXPORT_TAGS);" although the new way would be just to declare them with "our" in the same way you declare with "my" or "local"
Jonathan
@Kino: doh, I got called away before finishing my last edit. Fixed now.
Ether
+3  A: 

In general, OO Perl and Exporter are normally kept separate instead of mixing them together. This is one of the reasons why.

Like brian said, you'll have a much easier time getting this to work in the first place and with extending it further in the future if you take all the crap you're exporting, turn it into class properties/methods, and get rid of Exporter completely. The simple fact that the way you want to do it requires you to import and re-export everything should be a big, flashing clue that there's probably a better way to do it (i.e., a way that doesn't involve Exporter).

Dave Sherohman
I realize that it is not the best idea and I plan to find another method. I did, however, assume that perl exports variables automatically when using OOP, but I'm starting to understand why this is a bad idea. I will find another way, but I at least for now I know how I COULD do it (import than export again), but only if completely necessary.
Jonathan