@ISA specific to instance rather than class?

M

Matthew Braid

Hi all,

I'm streamlining one of my own packages by splitting off optional
functionality into sub-packages and only use base'ing them when
required, eg:

sub use_something {
my $self = shift;
eval {use base qw/My::package::Something/};
die $@ if $@;
return 1;
}

This works well, but it means that once one instance of the class uses
the 'something', then all of them have it loaded on creation.

I'm not worried about this, but I was wondering if there is a way to
make an instance of an object use an extra base package without the
whole class doing so.

(Oh, and yes I know about AutoSplitting, but its kind of messy and much
harder to write installers for, and results in pretty much the same
thing anyway)

Any ideas? (As I said - not bothered if there is no way :) )

MB
 
T

Tassilo v. Parseval

Also sprach Matthew Braid:
I'm streamlining one of my own packages by splitting off optional
functionality into sub-packages and only use base'ing them when
required, eg:

sub use_something {
my $self = shift;
eval {use base qw/My::package::Something/};
die $@ if $@;
return 1;
}

This works well, but it means that once one instance of the class uses
the 'something', then all of them have it loaded on creation.

I'm not worried about this, but I was wondering if there is a way to
make an instance of an object use an extra base package without the
whole class doing so.

Not really, no. But what you can do is creating a new class on the fly
with the desired characteristics and rebless your object into this
class:

sub make_subclass_of {
my ($self, @classes) = @_;
my @chars = ('a' .. 'z');
my $newclass;
$newclass .= $chars[rand @chars] for 1 .. 8;
no strict 'refs';
@{ "__${newclass}::ISA" } = (ref($self), @{ ref($self)."::ISA" }, @classes);
bless $self => "__$newclass";
}

And now you can do

$object->make_subclass_of( qw(Class1 Class2) );

$object is now blessed into a new class which inherits from the previous
class of $object, its superclasses and the two classes Class1 and
Class2. In order to avoid clashes, the new class name is a random string
such as '__lmcpnuvj'. This should ensure that no two objects get
reblessed into the same class although this could of course still happen
by coincidence.

Even though Perl allows such things, I wouldn't recommend them.

Tassilo
 
U

Uri Guttman

TvP" == Tassilo v Parseval said:
$object is now blessed into a new class which inherits from the
previous class of $object, its superclasses and the two classes
Class1 and Class2. In order to avoid clashes, the new class name is
a random string such as '__lmcpnuvj'. This should ensure that no two
objects get reblessed into the same class although this could of
course still happen by coincidence.

or bless it into a dynamically made class name which has the address of
the object inside it. this is guaranteed to be unique and is done in
wacko OO modules such as Class::Classless.
Even though Perl allows such things, I wouldn't recommend them.

using one of those modules makes it easier for each object to be its own
class and to have its own @ISA.

uri
 
M

Malte Ubl

Matthew said:
Hi all,

I'm streamlining one of my own packages by splitting off optional
functionality into sub-packages and only use base'ing them when
required, eg:

sub use_something {
my $self = shift;
eval {use base qw/My::package::Something/};


This to not defer the use statement until after compile time. You were
probably thinking og the eval "" form.

malte

PS: Changing Super-Classes at runtime is probably not the best thing to
do. Take a look at the decorator pattern for a more robust way to
implement this behaviour.
 
B

Ben Morrow

Matthew Braid said:
sub use_something {
my $self = shift;
eval {use base qw/My::package::Something/};

As someone else pointed out, a 'use' statement is a BEGIN block, so
this is silly. What you perhaps meant was
eval {
require qw/My::package::Something/;
@ISA = qw/My::package::Something/
}
die $@ if $@;
return 1;
}

This works well, but it means that once one instance of the class uses
the 'something', then all of them have it loaded on creation.

I think you have perhaps misunderstood how 'require' works: the module
file is only loaded and compiled *once*, the first time it is required
(used). Thereafter, giving your objects extra base classes has no
effect beyond the extra entries in @ISA.

Ben
 
M

Malcolm Dew-Jones

Ben Morrow ([email protected]) wrote:
: > sub use_something {
: > my $self = shift;
: > eval {use base qw/My::package::Something/};

: As someone else pointed out, a 'use' statement is a BEGIN block, so
: this is silly. What you perhaps meant was
: eval {
: require qw/My::package::Something/;
: @ISA = qw/My::package::Something/
: }

No, what he meant was that it needed to be a string eval.

eval 'use base qw/My::package::Something/';

(or better because of a bit more syntax checking, as long as you remember
the "q")

eval q{use base qw/My::package::Something/};

The string form of eval is evaluated at run time, which means the "use"
statement is _not_ evaluated as per a BEGIN block, and yet it still
includes what ever chicanery is going on in the background (importing,
exporting etc.)
 
M

Matthew Braid

Malcolm said:
Ben Morrow ([email protected]) wrote:
: > sub use_something {
: > my $self = shift;
: > eval {use base qw/My::package::Something/};

: As someone else pointed out, a 'use' statement is a BEGIN block, so
: this is silly. What you perhaps meant was
: eval {
: require qw/My::package::Something/;
: @ISA = qw/My::package::Something/
: }

No, what he meant was that it needed to be a string eval.

eval 'use base qw/My::package::Something/';

(or better because of a bit more syntax checking, as long as you remember
the "q")

eval q{use base qw/My::package::Something/};

The string form of eval is evaluated at run time, which means the "use"
statement is _not_ evaluated as per a BEGIN block, and yet it still
includes what ever chicanery is going on in the background (importing,
exporting etc.)

Damn I hate my newsgroup provider - I'm missing a few messages...

Anyway, I didn't realise that use inside eval{} was still evaluated at
compile time. Sigh. I've learnt to avoid eval'' so I might go for the

eval {
require qw/My::package::Something/;
push @ISA, qw/My::package::Something/;
};

form (unless require is evaluated at compile time inside an eval as well...)

I like the idea of re-blessing an object into its own private class
though. I might look into that further (I'll be digging into
Class::Classless a bit :) )

Thanks for the help.

MB
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top