[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]

Re: protected.pm (more Class::Fields)



> Sam Tregar:
> >  I mean, what does inheritence mean if it doesn't mean
> > that you can "cast" a Bar into a Foo with no problems?

        "Then what is OO for?" Prince Tregar demanded wildly. "What use is
inheritance if it cannot cast to a superclass?"  He gripped the magician's
shoulder hard to keep from falling.
        Schwern did not turn his head.  With a touch of sad mockery in
his voice, he said, "That's what pseudohashes are for".


Ah ha!  Therein lies the crux of the problem that this mess is trying
to solve.  The problem of key collision.  You're absolutely correct,
you should be able to cast a class into one of its super classes
without worrying about trampling over each other's private data.

Actually, lied in my last example.  There -is- a way to get it to work.

package Foo;
use fields qw(_whatever);

sub new {
        my($proto) = shift;
        my($class) = ref $proto || $proto;

        bless [\%{$class.'::FIELDS'}], $class;
}

sub whatever {
        # NOTE we explicitly cast $self to class Foo.
        my Foo $self = shift;
 
        # Now instead of looking at $self->[$self->[0]{_whatever}]
        # it does $self->[$Foo::FIELDS{_whatever}]
        print $self->{_whatever};
}

package Bar;
use base qw(Foo);

$bar = Bar->new;
$bar->whatever;  # This now works!


Here's what happens.  Normally, a pseudohash converts itself to an array
at run-time.  So if we declare a simple pseudohash:

        $phash = [{foo => 1}];

and use it like a hash:

        $phash->{foo} = "Bar";

that gets translated at run-time to:

        $phash->[ $phash->[0]{foo} ] = "Bar";

which works out to:

        $phash->[1] = "Bar";


BUT!  If we explictly cast a pseudohash to a class:

        my Foo $phash = [{foo => 1}];

Something different happens.  Instead of using $self->[0] to translate
itself into an array call, it uses %Foo::FIELDS!

        $self->{foo} = "Bar";

gets translated at *compile-time* to:

        $self->[$Foo::FIELDS{foo}] = "Bar";

totally ignoring $self->[0].  So we get the effect of casting a
class into its superclass, as expected!

However, there are a few problems with the existing implementation.
You can't have a class inherit from another with public fields of the
same name (although I think this might be a feature).  ie. this
doesn't fly:

        package Foo;
        use fields qw(foo);

        package Bar;
        use base qw(Foo);
        use fields qw(foo);

(It either dies or throws a warning, I forget.)

The much bigger problem is that multiple field inheritance doesn't work.

        package Foo;
        use fields qw(foo);

        package Moo;
        use fields qw(you);

        package Bar;
        use base qw(Foo Moo);

That just dies for reasons I'm not going to get into because its too
complicated for 4am.  However, I might have a solution, but that's
also too complicated for 4am.

-- 

Michael G Schwern                                           schwern@pobox.com
                    http://www.pobox.com/~schwern
     /(?:(?:(1)[.-]?)?\(?(\d{3})\)?[.-]?)?(\d{3})[.-]?(\d{4})(x\d+)?/i


References to:
"Matthias Urlichs" <smurf@noris.de>

[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index][Thread Index][Top&Search][Original]