This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Objects : Hierarchical calls to initializers and destructors =head1 VERSION Maintainer: Damian Conway <[EMAIL PROTECTED]> Date: 1 September 2000 Mailing List: [EMAIL PROTECTED] Version: 1 Number: 189 Status: Developing =head1 ABSTRACT This RFC proposes a new special method called C<SETUP> that is invoked automagically whenever an object is created. Furthermore, it proposes that both C<SETUP> and C<DESTROY> methods should be invoked hierarchically in all base classes. =head1 DESCRIPTION One of the major limitations of object-oriented Perl is that, unlike most other OO languages, it does not automatically invoke the initializers and destructors of base classes, when initializing or destructing an object of a derived class. This leads to tediously complex code in constructors and destructors in order to manually achieve the same effect. More often, it leads to bugs. It is proposed that Perl 6 introduce an automatic object initialization mechanism, analogous to the automatic object clean-up mechanism provided by C<DESTROY> methods. It is further proposed that both the initialization and destruction mechanisms automatically call their corresponding base class versions to ensure that complete initialization and destruction of derived objects occurs correctly. =head2 The C<SETUP> method It is proposed that, if a class has a method named C<SETUP>, that method will be invoked automatically during any call to C<bless>. It is further proposed that C<bless> be extended to take an optional argument list after its second argument, and that this list would be passed to any C<SETUP> method invoked by the C<bless>. The typical constructor would then be reduced to: package MyClass; sub new { bless {}, @_ } with initialization handled in a separate C<SETUP> routine: sub SETUP { my ($self, @ctor_data) = @_; # initialization of object referred to by $self occurs here } =head2 Hierarchical C<SETUP> calls It is proposed that when an object is blessed, I<all> of the C<SETUP> methods in any of its base classes are also called, and passed the argument list appended to the invocation of C<bless>. C<SETUP> methods would be called in depth-first, left-most order (i.e. ancestral C<SETUP> methods would be called before derived ones). Any given C<SETUP> method would only be called once for the same object, no matter how many separate paths its class might be inherited through. For example, given the following class hierarchy: package Base1; sub new { bless {}, @_ } sub SETUP { print "Base1::SETUP : @_\n" } package Base2; sub SETUP { print "Base2::SETUP : @_\n" } package Base3; sub SETUP { print "Base3::SETUP : @_\n" } package Derived1; use base qw(Base1 Base2); sub SETUP { print "Derived1::SETUP : @_\n" } package Derived2; use base qw(Base2 Base3); sub SETUP { print "Derived2::SETUP : @_\n" } package Rederived1; use base qw(Derived1 Derived2); sub SETUP { print "Rederived1::SETUP : @_\n" } then the call to: $obj = Rederived->new(1..3) would print: Base1::SETUP : 1 2 3 Base2::SETUP : 1 2 3 Derived1::SETUP : 1 2 3 Base3::SETUP : 1 2 3 Derived2::SETUP : 1 2 3 Rederived1::SETUP : 1 2 3 Note in particular that C<Base2::SETUP> is only called once (as early as possible), even though class Rederived inherits it through two distinct paths. =head2 Hierarchical C<DESTROY> calls It is further proposed that when an object's destructor is invoked, all inherited destructors would also be invoked, in depth-I<last>, right-most order. Again, each C<DESTROY> for an object would be called exactly once, regardless of how many different paths it is inherited through. For example, given the following class hierarchy (with the same topology as the example for C<SETUP> above): package Base1; sub new { bless {}, @_ } sub DESTROY { print "Base1::DESTROY\n" } package Base2; sub DESTROY { print "Base2::DESTROY\n" } package Base3; sub DESTROY { print "Base3::DESTROY\n" } package Derived1; use base qw(Base1 Base2); sub DESTROY { print "Derived1::DESTROY\n" } package Derived2; use base qw(Base2 Base3); sub DESTROY { print "Derived2::DESTROY\n" } package Rederived1; use base qw(Derived1 Derived2); sub DESTROY { print "Rederived1::DESTROY\n" } then the destruction of an object: $obj = "something else"; would print: Rederived1::DESTROY Derived2::DESTROY Base3::DESTROY Derived1::DESTROY Base2::DESTROY Base1::DESTROY Note that C<Base2::DESTROY> is only called once (as late as possible), even though class Rederived inherits it through two distinct paths. Note too that the C<DESTROY> invocation sequence is the exact reverse of the sequence for C<SETUP>. =head2 Proposed standard C<UNIVERSAL::new> Given that most Perl classes are hash-based and that the C<SETUP> method cleanly separate construction and initialization, it might be desirable to have the UNIVERSAL class always supply a default constructor: package UNIVERSAL; sub new { bless {}, @_ } If this were provided, many classes could simply define an appropriate C<SETUP> method and simply inherit their constructor. =head1 MIGRATION Changes to the behaviour of DESTROY might have serious impact on code that overrides destructors in derived classes, especially if the overridden destructor delegates explicitly to its base class counterpart. =head1 IMPLEMENTATION Not difficult. =head1 REFERENCES I<perltoot> Conway, I<Object Oriented Perl>, pp. 171-178.
