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

Discussion in 'Perl Misc' started by Alfred Z. Newmane, Apr 29, 2005.

  1. 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.) **
    Alfred Z. Newmane, Apr 29, 2005
    #1
    1. Advertising

  2. Alfred Z. Newmane wrote:
    > 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
    Mark Clements, Apr 29, 2005
    #2
    1. Advertising

  3. 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
    --
    use bigint;
    $n=71423350343770280161397026330337371139054411854220053437565440;
    $m=-8,;;$_=$n&(0xff)<<$m,,$_>>=$m,,print+chr,,while(($m+=8)<=200);
    Tassilo v. Parseval, Apr 29, 2005
    #3
  4. Tassilo v. Parseval wrote:
    > 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
    Mark Clements, Apr 29, 2005
    #4
  5. Alfred Z. Newmane <> wrote:

    > 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.


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
    Tad McClellan, Apr 29, 2005
    #5
  6. Mark Clements wrote:
    > Tassilo v. Parseval wrote:
    >> 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.
    Alfred Z. Newmane, Apr 29, 2005
    #6
  7. Alfred Z. Newmane wrote:
    > Mark Clements wrote:


    >>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?)
    >

    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
    Mark Clements, May 2, 2005
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. John Nagle
    Replies:
    3
    Views:
    289
    John Nagle
    Feb 25, 2007
  2. rp
    Replies:
    1
    Views:
    493
    red floyd
    Nov 10, 2011
  3. Tony N.

    Printing an array of hash refs

    Tony N., Sep 22, 2004, in forum: Perl Misc
    Replies:
    11
    Views:
    205
    Tony N.
    Sep 24, 2004
  4. Bryan
    Replies:
    6
    Views:
    198
    -berlin.de
    Apr 11, 2007
  5. Replies:
    3
    Views:
    253
    J├╝rgen Exner
    May 13, 2008
Loading...

Share This Page