On Fri, Sep 01, 2000 at 08:59:10PM -0000, Perl6 RFC Librarian wrote:
> =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.

I agree with Michael that SETUP should be BLESS.  You argue that it
"doesn't do any blessing", ignoring Michael's point about PRINT not
(necessarily) doing any printing.

As you pointed out in the 'MIGRATION' section, such a radical change
to the meaning of DESTROY [w]ould have serious impact.  I contend that
a name other than DESTROY should be chosen for recursive-destructor
role.  I like CURSE, though maybe ABSOLVE will better please the
unperverted among us.  Then object reblessing would naturally call
CURSE via the old package and BLESS with the new.  If reblessing is
not itself condemned, that is.

  use base map { "Base$_" } 1 .. 999;
  {
     my $x = bless {}; # a thousand blessings
  }                    # a thousand curses (m+s vs refcounting aside)


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

Every base's SETUP gets the same argument list?  That seems highly
undesirable from an OO-purity standpoint.  Or do you have a syntax for
member initializer lists in store for us?

Better, have UNIVERSAL::new load the args into a hash and pass it to
SETUPs by reference, avoiding positional-parameter hell.  SETUP can
delete what it processes and insert what its bases need.
UNIVERSAL::new can even warn about "unrecognized initializer arg" if
there's anything left in the hash when SETUPs have finished.  See my
experimental UNIVERSALs below.

> Note that C<Base2::DESTROY> is only called once (as late as possible),
> even though class Rederived inherits it through two distinct paths.

Let's get the single-inheritance case nailed down before we think
about how it should work in MI.  With Perl's interface inheritance (a
term for which I thank you, Damian), who knows?  Maybe some base
classes don't want to be virtual.

> =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 {}, @_ }

Yes, and it could call SETUP the way you want, eliminating the need to
change the 'bless' builtin.  There could even be a UNIVERSAL::SETUP
that looks for args from %FIELDS (or its successor) in its initalizer
hash.  Below is something along these lines that I put together last
year.  It relies on pseudohash semantics, but the principles are
what's of interest.

    package JTobey::UNIVERSAL;

    sub new {
        if (scalar(@_) =~ /[02468]$/) {
            require Carp;
            Carp::confess ("Missing value for last initializer");
        }

        my ($pkg, %args) = @_;
        my ($obj, $fields);

        { no strict 'refs'; $fields = \%{"$pkg\::FIELDS"}; }
        $obj = bless [$fields], $pkg;
        $obj->init (\%args);

        if (%args) {
            require Carp;
            Carp::croak ("Initializer list contains unrecognized fields: "
                         .join(", ", keys %args));
        }
        return $obj;
    }

    sub init {
        my ($obj, $argsref) = @_;
        my ($fields, $pos);

        $fields = $$obj[0];
        foreach my $name (keys %$argsref) {
            next if not $pos = $$fields{$name};
            $$obj[$pos] = delete $$argsref{$name};
        }
    }

    # Break circular references.
    sub free {
        @ { $_[0] } = ();
    }

-John

Reply via email to