nmerriweather has asked for the wisdom of the Perl Monks concerning the following question:

I have a rather large app. what i've realized is that A LOT of my code is new declarations (i'd say probably 5% of my code, which is ~50k w/1mb of memory resident mod_perl )

is it safe to inherit the constructor from the parent class(es chain).

ie: MyPackage, MyPackage::aaa, MyPackage::aaa::bbb, MyPackage::aaa::bbb::ccc, MyPackage::aaa::bbb::ccc:ddd all use the same constructor code for 'new'

is it safe to elminate the new and just inherit? at one point someone told me that was a bad idea, so i never thought of it again -- but i've since seen some of their coding practices, and well, my beliefs in terms of what they told me are now all in question.

Replies are listed 'Best First'.
Re: class inheritance and new(constructor)
by Ieronim (Friar) on Jul 16, 2006 at 19:02 UTC
    Directly from perlbot:
    An inheritable constructor should use the second form of bless() which allows blessing directly into a specified class. Notice in this example that the object will be a BAR not a FOO, even though the constructor is in class FOO.
    package FOO; sub new { my $type = shift; my $self = {}; bless $self, $type; } sub baz { print "in FOO::baz()\n"; } package BAR; @ISA = qw(FOO); sub baz { print "in BAR::baz()\n"; } package main; $a = BAR->new; $a->baz;
    There is IMO nothing to add :) Re-using constructors is generally a good idea, as it makes the code more maintainable.

         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
      ok. sweet.
      my system is pretty much set up just like that. i tested it out and it worked before having posted here
      since its in perlbot, i figure thats a good sign that its a safe coding practice and not just something that works.
Re: class inheritance and new(constructor)
by ikegami (Patriarch) on Jul 16, 2006 at 19:07 UTC

    I like to initialize (and create) my fields in the constructor (even if only to undef), so my subclass constructors would look like:

    my new { my ($class, ...) = @_; my $self = $class->SUPER::new(...); $self->{...} = ...; $self->{...} = ...; return $self; }

    or

    use constant IDX_... => Parent::NEXT_IDX() + 0; use constant IDX_... => Parent::NEXT_IDX() + 1; use constant NEXT_IDX => Parent::NEXT_IDX() + 2; my new { my ($class, ...) = @_; my $self = $class->SUPER::new(...); push(@$self, ..., # IDX_... ..., # IDX_... ); return $self; }

    depending whether it's a hash- or array-based object.

    Nothing requires this, however. I could rely on the fact that non-existant hash and array fields evaluate to undef, but I prefer the self-documenting properties of my method.

Re: class inheritance and new(constructor)
by shonorio (Hermit) on Jul 16, 2006 at 23:45 UTC
    I use, and recomend, Class::Std and Class::Std::Utils, or Moose than a pseudohashes OO based to implement best practices and more (and best) control over access of variables and values, constructors and destructors of my class.

    Theses modules implement, and recomend you to use specials methods (BUILD and DEMOLISH) to be a constructors and destructors of your class. Theses build-in methods will manager all the class hierarchies and inheritance works.

    If you don't know theses modules, I strong recomend you to take a look of them.

    Solli Moreira Honorio
    Sao Paulo - Brazil
      Class::Std and friends are of course the modules written by Damien Conway and endorsed in his "Perl Best Practices" book. These are one way of doing "inside-out objects", which have the advantage of encapsulated internal state (with hash based objects you can access a field of the hash directly if you feel like cheating, with inside-out objects you're forced to use the accessors).

      I haven't played with this concept much myself: they sound neat, but I think they're still a little too new. For example, there's some debate about whether "Class::Std" is really the right way to do it. I quote from the documentation for Class::InsideOut:

      * Class::Std -- Despite the name, this does not reflect currently known best practices for inside-out objects. Does not provide thread-safety with CLONE and doesn't support foreign inheritance. Has a robust inheritance/initialization system.
Re: class inheritance and new(constructor)
by doom (Deacon) on Jul 16, 2006 at 23:04 UTC
    There's a possible problem with this sort of thing that you might want to think about: in perl, only the first "new" found in a chain of inheritence is going to be called.

    Damien Conway presents a system where initialization is broken out into "_init" subs, and the "new" is inherited from a "mixin" class. The idea there is that the child _init's can explicitly call the "_inits" of the parent class.

    See the book "Object Oriented Perl" (published by Manning), Chapter 6 "Inheritanced", listing 6.1 on page 174.

      I like to use a simplified version of this (excellent) concept. I try to have only one simpele new method in the base class (and my apps try to have only one base class a la Objective-C/Java etc.) which calls an _init method for the initialisation tasks. It seems to work fairly well for me. Eg:

      package MyApp::BaseClass; sub new { my $class = shift; my $init_args = shift; # a real example would have warnings etc. here. ref $init_args eq 'HASH' || $init_args = {}; my $self = { _init => $init_args }; bless $self, $type; # self is re-assigned to allow the _init to replace itself $self = $self->_init() || UsefullErrorObject->new({ class => $class, args => $i +nit_args }); return $self; } sub _init { my $self = shift; # subclass this # first hashref argument to new() is in $self->{_init} return $self; }
      A real benefit of this setup is that since you never sublass new() you can always guarantee that new() will return an object (possibly an error object) which removes the need to test every object creation with an if defined type test.

      Season to suit.

Re: class inheritance and new(constructor)
by Anonymous Monk on Jul 18, 2006 at 08:06 UTC
    its okay