Multiple Inheritance: mixed base class refs (hash, array)

A

Alfred Z. Newmane

I noticed when trying to inherit from IO::Select along with a class that
I've written (an event handling class, that uses the moral HASH style
class container, for use with bless.)

A skeleton example of my Event class:

package MyEvent;
use strict;

sub new { # Constructor.
my ($this, $obj) = (
shift,
{ Events => { } }
);

my $class = ref($this) || $this;
return bless $obj, $class;
}


I noticed that IO:Select actually uses an ARRAY ref (blessed), rather
than a HASH ref, to contain itself. Why is this?

It seems to make it rather difficult to inherit from:


1 package MySelect;
2 use strict;
3 use IO::Select;
4 use MyEvent;
5 our @ISA = qw(IO::Select MyEvent);
6
7 sub new {
8 my $this = shift;
9 my $class = ref($this) || $this;
10
11 my $select = new IO::Select(@_);
12 my $event = new MyEvent(@_);
13
14 print "[". ($event), "]\n[". ($select), "]\n";
15
16 my $obj = { @$select, %$event };
17 }


This prints:

[MyEvent=HASH(0x81705e8)]
[IO::Select=ARRAY(0x80fbb4c)]
Use of uninitialized value in anonymous hash ({}) at SR/Select.pm
line 16.

This error message seems a little misleading. Why is it claiming it is
uninitialized? If I remove @$select from that line, then the error no
longer occurs. From the 2nd line of output, it is clear IO::Select is a
blessed ARRAY ref rather than a HASH ref.


* NOTE: These are just a very simplified versions of my classes,
stripped down to the bare minimum that illustrates the problem. I find
that to be infinitely more useful than posting several pages of code :)
*


What is the best way to go about this? I've never actually ran into a
class that uses an ARRAY as it's internal container. All others I've
encountered all bless a HASH. I was previously unaware that one could
actually bless an ARRAY instead.

Thank you for any insight on this, I find this to be an interesting
topic, which does not appear to have been talked about around before, at
least I could not find anything on this via google groups.

** (And yes I've looked through the FAQs as well as
perltoot/tootc/bot/boot/obj/etc. I pride myself at going to great
lengths to solve my problem before considering, and thought this might
be worthy of bringing up in this group.) **
 
M

Mark Clements

Alfred said:
I noticed when trying to inherit from IO::Select along with a class that
I've written (an event handling class, that uses the moral HASH style
class container, for use with bless.)
Noticed what? :)
A skeleton example of my Event class:

package MyEvent;
use strict;

sub new { # Constructor.
my ($this, $obj) = (
shift,
{ Events => { } }
);

my $class = ref($this) || $this;
return bless $obj, $class;
}


I noticed that IO:Select actually uses an ARRAY ref (blessed), rather
than a HASH ref, to contain itself. Why is this?

It seems to make it rather difficult to inherit from:


1 package MySelect;
2 use strict;
3 use IO::Select;
4 use MyEvent;
5 our @ISA = qw(IO::Select MyEvent);
6
7 sub new {
8 my $this = shift;
9 my $class = ref($this) || $this;
10
11 my $select = new IO::Select(@_);
12 my $event = new MyEvent(@_);
13
14 print "[". ($event), "]\n[". ($select), "]\n";
15
16 my $obj = { @$select, %$event };
17 }


This prints:

[MyEvent=HASH(0x81705e8)]
[IO::Select=ARRAY(0x80fbb4c)]
Use of uninitialized value in anonymous hash ({}) at SR/Select.pm
line 16.

This error message seems a little misleading. Why is it claiming it is
uninitialized? If I remove @$select from that line, then the error no
longer occurs. From the 2nd line of output, it is clear IO::Select is a
blessed ARRAY ref rather than a HASH ref.
<snip>

It's an array ref because it is a pseudohash (or pseudo-hash). Check out

perldoc fields

for starters. Also, your constructor method doesn't initialize properly:
you are confusing inheritance and composition.

In the former (which you have tried to set up with "our @ISA" (though
you could have used "use base")), you would need to do your
initialization something like this.


sub new {
my $class = shift;

my $self = $class->SUPER::new();

return $self;

}

This doesn't really work for multiple inheritance though.

With composition, your class isn't a subclass, but contains references
to the other classes.


sub new {
my $class = shift;
my $argsForEvent = shift;
my $argsForSelect = shift;

my $self = {
_event => MyEvent->new( @$argsForEvent ),
_select => IO::Select->new( @$argsForSelect ) ,
};

return bless $self,$class;
}


Note I am not passing @_ as the argument to the constructors as it is
unlikely that MyEvent->new and IO::Select->new will take the same arguments.

Mark
 
T

Tassilo v. Parseval

Also sprach Mark Clements:
Alfred Z. Newmane wrote:
[...]
I noticed that IO:Select actually uses an ARRAY ref (blessed), rather
than a HASH ref, to contain itself. Why is this?
[...]

It's an array ref because it is a pseudohash (or pseudo-hash). Check out

perldoc fields

It isn't. It just happens to be a plain array-reference because it is
a fairly natural choice of data-structures when it comes to maintaining
a list of file-descriptors. It however mimics pseudo-hashes to a certain
extent in that IO::Select uses named constants to access the first three
fields of the array.

Tassilo
 
M

Mark Clements

Tassilo said:
Also sprach Mark Clements:

Alfred Z. Newmane wrote:

[...]

I noticed that IO:Select actually uses an ARRAY ref (blessed), rather
than a HASH ref, to contain itself. Why is this?

[...]


It's an array ref because it is a pseudohash (or pseudo-hash). Check out

perldoc fields


It isn't. It just happens to be a plain array-reference because it is
a fairly natural choice of data-structures when it comes to maintaining
a list of file-descriptors. It however mimics pseudo-hashes to a certain
extent in that IO::Select uses named constants to access the first three
fields of the array.

Tassilo

Oops - I completely misread the output of Data::Dumper. I tend to use
pseudo-hashes for my own classes, so I guess I have conditioned myself
(badly) to see them even where they are not present :(

Mark
 
T

Tad McClellan

Alfred Z. Newmane said:
Use of uninitialized value in anonymous hash ({}) at SR/Select.pm
line 16.

This error message


It is not an error message.

It is a warning message.
 
A

Alfred Z. Newmane

Mark said:
Tassilo said:
Also sprach Mark Clements:
Alfred Z. Newmane wrote:
[...]

I noticed that IO:Select actually uses an ARRAY ref (blessed),
rather than a HASH ref, to contain itself. Why is this?
[...]

It's an array ref because it is a pseudohash (or pseudo-hash).
Check out perldoc fields

It isn't. It just happens to be a plain array-reference because it is
a fairly natural choice of data-structures when it comes to
maintaining a list of file-descriptors. It however mimics
pseudo-hashes to a certain extent in that IO::Select uses named
constants to access the first three fields of the array.

Oops - I completely misread the output of Data::Dumper. I tend to use
pseudo-hashes for my own classes, so I guess I have conditioned myself
(badly) to see them even where they are not present :(

Thank you for those descriptions and sample code. I have only one
remaining question, concerning the code you have shown in your previous
post:
This doesn't really work for multiple inheritance though.

With composition, your class isn't a subclass, but contains references
to the other classes.


sub new {
my $class = shift;
my $argsForEvent = shift;
my $argsForSelect = shift;

my $self = {
_event => MyEvent->new( @$argsForEvent ),
_select => IO::Select->new( @$argsForSelect ) ,
};

return bless $self,$class;
}

Yes I could of done it this way. but I was really wondering if it would
be possible to accomplish this with inheritance, some how combine the
two base classes into one big class. Would it be possible to "convert"
(for lack of a better term) the "pseudo-hashes" returned by IO::Select
into a more standard HASH (ref), *without* compromising the IO::Select
class itself (meaning, can the values be fed into the $obj hashref and
then still be able to use an inherited subs of IO::Select?)

Thank you again for you responses.
 
M

Mark Clements

Alfred said:
Mark Clements wrote:


Yes I could of done it this way. but I was really wondering if it would
be possible to accomplish this with inheritance, some how combine the
two base classes into one big class. Would it be possible to "convert"
(for lack of a better term) the "pseudo-hashes" returned by IO::Select
into a more standard HASH (ref), *without* compromising the IO::Select
class itself (meaning, can the values be fed into the $obj hashref and
then still be able to use an inherited subs of IO::Select?)
Multiple inheritance raises all sorts of questions in OO programming. In
fact, some languages forbid it. (They aren't pseudo-hashes by the way, I
was wrong. See Tassilo's post). There is no advantage to be gained by
trying to convert the blessed arrayref returned by IO::Select's
constructor into something else, in fact one of the points of OO
programming (encapsulation) is that the underlying implentation of an
object is hidden and unimportant as regards the functionality of a
class. Classes can (and should, in a lot of cases), be treated as
black-boxes.

As I've said, you can't create a class that inherits from both parent
classes transparently because the constructors will clash. If you really
do need inheritance from both classes (composition is much more
straightforwrd to implement), then you will need to override the
constructor methods (breaking the interface from a functional
perspective ) so that you can pass both sets of arguments in.
I don't know how you'd reconcile the need to call $class->SUPER::new()
for each parent class.


Mark
 

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,763
Messages
2,569,562
Members
45,038
Latest member
OrderProperKetocapsules

Latest Threads

Top