FAQ
Today, I was doing some mucking about with class data, generated packages, and
Class::ISA, and I started to wail and gnash my teeth. I cried, "Why can't I
just replaced the darn object system?"

It would let me use any kind of MRO I wanted, including some crazy MRO that I
only want in one extreme case. It would let me do truly classless OO, avoiding
the pseudo-anonymous "classes" created by things like Package::Generator. It
would let me have a clear distinction between class and object methods.

A truly anemic start would be to write classes with no methods save for
AUTOLOAD. Unfortunately, AUTOLOAD does not catch universal methods. This is
worse than just having to write a "can" and "isa." If anything in your process
loads UNIVERSAL::{moniker,require} or Sub::Install, or any of a number of other
things that muck with UNIVERSAL, your code will change in bizarre ways.

What if, instead, I could overload method calls on an object?

package Classless::Root;
use overload method => 'invoke_method';

sub new {
my ($class, %attr) = @_;

my $root = { ... universal prototype ... };

my $obj = { parent => $root, attr => \%attr };
return bless $obj => $class;
}

sub invoke_method {
my ($self, $name, $arg_ref) = @_;

my $iter = (ref $self)->parent_climber($self);
while (my $obj = $iter->next) {
next unless exists $obj->{attr}{$name};
$obj->{attr}{$name}->(@$arg_ref);
}
}

Other class construction kits could use this to produce class objects.

my $class = Class::Metameta->new({ ...class definition... });
my $instance = $class->new({ ...instance data... });

These might both be objects blessed into Class::Metameta. The bless target
(the result of "ref") would now refer not specifically to the object's class in
the traditional sense, but to the package in which the object's behavior would
be defined -- either as a "traditional" Perl class or as a method dispatching
system.

I imagine this would confuse calling (UNIVERSAL::isa(x)), but it's hard to
care. It would also mean that UNIVERSAL would only be the default for
"default" classes. I think that's a benefit, rather than a problem. I have a
nagging suspicion that making this work with indirect method calls would be
obnoxious. Again, I have a hard time seeing that as a problem. It could be
documented.

So, what I'm wondering is:

a) am I totally wrong and stupid? please point out how and why

b) how difficult would this be to accomplish?

--
rjbs

Search Discussions

  • Aristotle Pagaltzis at May 6, 2008 at 5:36 pm

    * Ricardo SIGNES [2008-05-06 19:05]:
    a) am I totally wrong and stupid? please point out how and why
    All I have to say is I’ve always wanted something like this.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>
  • Ricardo SIGNES at May 6, 2008 at 5:59 pm
    * Aristotle Pagaltzis [2008-05-06T13:36:45]
    * Ricardo SIGNES [2008-05-06 19:05]:
    a) am I totally wrong and stupid? please point out how and why
    All I have to say is I’ve always wanted something like this.
    mst pointed out that "autobox leads the way," but autobox can't do:

    my $method = 'blort';
    $obj->$method;

    ...and I think that is critical.

    It also can't do $obj->$coderef, and I'm not sure what we'd want to do with
    $object->fqmn;

    It seems like in all cases: punt to the method call handler.

    --
    rjbs
  • Ævar Arnfjörð Bjarmason at May 6, 2008 at 7:08 pm

    On Tue, May 6, 2008 at 3:36 PM, Ricardo SIGNES wrote:
    What if, instead, I could overload method calls on an object?
    One of the first things I /wanted/ to do to the core but never found
    the time to implement was the blessing of refs into CODE instead of
    packages, that is:

    ----
    my $obj = bless [] => sub {
    my ($self, $name, @arg) = @_;
    warn ref($self) . " $name @arg";
    };

    $obj->moo(qw(foo boo))
    "ARRAY moo foo boo at line X"
    $obj->x(qw(y z));
    "ARRAY x y z at line X"
    ----

    a) I don't think the idea is stupid if I understand it correctly,
    would the alternate way I demonstrated accomplish what you want to do
    as well?

    b) Implementing /my/ way of doing it looked difficult, the way I
    thought of doing it was changing everything that uses a stash now to
    using a refcounted SV* which would be a huge task that would break all
    sorts of things. But if I was going to do it now that I'm somewhat the
    wiser in internals I'd look at the method dispatch mechanism, maybe
    attach the CODE as a new kind of magic and put some stub in the stash.
  • Ricardo SIGNES at May 6, 2008 at 7:19 pm
    * Ævar Arnfjörð Bjarmason [2008-05-06T15:08:10]
    my $obj = bless [] => sub {
    my ($self, $name, @arg) = @_;
    warn ref($self) . " $name @arg";
    };

    [ ... ]
    ----

    a) I don't think the idea is stupid if I understand it correctly,
    would the alternate way I demonstrated accomplish what you want to do
    as well?
    It might be possible to do everything that way, but I think much more tedious.
    I mean, I love closures at least as much as the next guy, but I think this
    would be a pretty rough way to do things.

    Two simple-ish problems:

    a) what does ref return?

    b) how do I set up operator overloading?

    Then:

    If this was done with overload.pm, objects would get the overloaded method
    dispatch, but the packages their blessing referred to would not. That would
    make it really easy to say things like:

    use overload method => sub {
    my ($self, $method, $arg_ref) = @_;
    my $brain = ref $self;

    my $code = $brain->find_callback($method);
    $code->($self, $arg_ref);
    };

    which can use "simple" existing method dispatch to allow the "brain" to be
    subclassed.

    Doing this with blessed-into-code seems a bit more convoluted.

    --
    rjbs
  • Ævar Arnfjörð Bjarmason at May 7, 2008 at 2:53 am

    On 5/6/08, Ricardo SIGNES wrote:
    a) what does ref return?
    The return value could not make sense since the class would not be
    anonymous, or it would have to return something like "ARRAY" which
    would be worse.
    b) how do I set up operator overloading?
    You couldn't, I guess.
    Doing this with blessed-into-code seems a bit more convoluted.
    Indeed, I really hadn't thought it through:)
  • Rafael Garcia-Suarez at May 7, 2008 at 7:33 am

    2008/5/6 Ricardo SIGNES <perl.p5p@rjbs.manxome.org>:
    What if, instead, I could overload method calls on an object?

    package Classless::Root;
    use overload method => 'invoke_method';
    use overload '->' => \&invoke; # more graphic ?

    Let's try to think a bit more about this :

    * that would work only for instance methods, not class methods

    * that would step over AUTOLOADed methods -- AUTOLOAD would never
    be called in presence of -> overloading

    * would that step over regular, existing, defined methods ?
    If it doesn't, we can instruct invoke() to install new methods,
    à la AUTOLOAD.

    * We will need to avoid calling methods on the same object from inside
    invoke(), to avoid deep recursion.

    * What if someones invokes the "(->" method directly ? (the
    internal name of "invoke()".) Maybe all overload methods
    (whose names begin with "(") should be excluded from this
    mechanism.

    * We will probably want a nice way to throw the error "Can't locate
    object method %s via package %s", like a new builtin, or a core
    function in the overload package

    * Of course, subclasses will inherit that overloading.

    I'm not familiar with the implementation of overloading in the core.
    That doesn't sound like something really difficult to implement, but
    don't take my word for it.
  • Aristotle Pagaltzis at May 7, 2008 at 8:10 am

    * Rafael Garcia-Suarez [2008-05-07 09:35]:
    use overload '->' => \&invoke; # more graphic ? ++
    * that would work only for instance methods, not class methods
    I think Ricardo considers that a feature; I can see that point of
    view, but perosnally I’m not sure yet. I think it would be nice
    if there was a way to get both, but separately from each other.
    * that would step over AUTOLOADed methods -- AUTOLOAD would
    never be called in presence of -> overloading
    Which is OK, since it can do everything AUTOLOAD can, and then
    some.
    * would that step over regular, existing, defined methods ?
    If it doesn't, we can instruct invoke() to install new
    methods, à la AUTOLOAD.
    I think sometimes you’d want it to and sometimes wouldn’t. Maybe
    an option à la `fallback` that lets you pick which behaviour you
    would prefer in this instance. Not sure what the default should
    be though.
    * We will need to avoid calling methods on the same object from
    inside invoke(), to avoid deep recursion.
    You just need to make sure the recursion bottoms out; same as
    using recursion in any other scenario.
    * What if someones invokes the "(->" method directly ? (the
    internal name of "invoke()".) Maybe all overload methods
    (whose names begin with "(") should be excluded from this
    mechanism.
    I’m not sure about `(->` specifically, but why exclude the other
    methods? If we assume that unusual dispatch rules are sometimes
    useful, wouldn’t this mean that unusual dispatch rules for op
    handlers would also sometimes be useful?
    * We will probably want a nice way to throw the error "Can't
    locate object method %s via package %s", like a new builtin,
    or a core function in the overload package
    That would be nice to have anyway – I’ve emulated that message in
    at least half of the (few) AUTOLOADs I’ve written.
    * Of course, subclasses will inherit that overloading.
    Sounds good to me.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>
  • Ricardo SIGNES at May 7, 2008 at 11:40 am
    * Rafael Garcia-Suarez [2008-05-07T03:33:40]
    2008/5/6 Ricardo SIGNES <perl.p5p@rjbs.manxome.org>:
    What if, instead, I could overload method calls on an object?

    package Classless::Root;
    use overload method => 'invoke_method';
    use overload '->' => \&invoke; # more graphic ?
    I thought about that, but I'm concerned that it looks like it might handle
    $obj->{foo} and $obj->[0].
    * that would work only for instance methods, not class methods
    I think that's totally fine. I think, in fact, that packages will be used to
    define behaviors (dare I say, metaclasses) and that classes will be objects of
    one sort and instances objects of another:

    $class = Class->new; # we get a Class object
    $obj = $class->new; # we get a (say) Class::Instance object, or maybe a
    Class with is_instance true. not a worry to me

    $obj2 = $obj->new; # method missing!
    * that would step over AUTOLOADed methods -- AUTOLOAD would never
    be called in presence of -> overloading
    That's fine. AUTOLOAD is part of the Old Style Method Dispatch. The method
    overload handler would get every single method call on instances. The only
    exception is th overload handler itself:

    use overload method => 'some_handler';

    $obj->foo(1,2,3);

    Now (ref $obj)::some_handler($obj, [ 1, 2, 3 ]) might be called (but as an
    old-style method) or we might call Class->some_handler($obj, $args). Not sure.
    Calling it on class might be simpliest, since the class MUST use old-style
    dispatch.

    We have to consider this case:

    package Class::Newstylee;
    use overload
    method => ...,
    '""' => 'method_name',
    fallback => 1;

    Does C<"$obj"> trigger $obj->method_name (overloaded dispatch) or
    $obj->method_name (old dispatch) or Class->method_name($obj) (yuck).
    * would that step over regular, existing, defined methods ?
    If it doesn't, we can instruct invoke() to install new methods,
    à la AUTOLOAD.
    Yes. *All* instance methods go to the handler.
    * We will need to avoid calling methods on the same object from inside
    invoke(), to avoid deep recursion.
    At the very least, we need to keep recursion in mind.
    * What if someones invokes the "(->" method directly ? (the
    internal name of "invoke()".) Maybe all overload methods
    (whose names begin with "(") should be excluded from this
    mechanism.
    I didn't know you could do this, so I haven't thought about it and have
    absolutely no idea yet.
    * We will probably want a nice way to throw the error "Can't locate
    object method %s via package %s", like a new builtin, or a core
    function in the overload package
    Yes! I really want Class::WhiteHole's functionality to be easy to get.
    * Of course, subclasses will inherit that overloading.
    As it should be! You can use old-style dispatch to implement a derived set of
    new-style dispatch behaviors!

    --
    rjbs
  • Reini Urban at May 7, 2008 at 10:19 am

    2008/5/6 Ricardo SIGNES <perl.p5p@rjbs.manxome.org>:
    Today, I was doing some mucking about with class data, generated packages, and
    Class::ISA, and I started to wail and gnash my teeth. I cried, "Why can't I
    just replaced the darn object system?"

    It would let me use any kind of MRO I wanted, including some crazy MRO that I
    only want in one extreme case. It would let me do truly classless OO, avoiding
    the pseudo-anonymous "classes" created by things like Package::Generator. It
    would let me have a clear distinction between class and object methods.

    A truly anemic start would be to write classes with no methods save for
    AUTOLOAD. Unfortunately, AUTOLOAD does not catch universal methods. This is
    worse than just having to write a "can" and "isa." If anything in your process
    loads UNIVERSAL::{moniker,require} or Sub::Install, or any of a number of other
    things that muck with UNIVERSAL, your code will change in bizarre ways.
    I would just write something along "no autoload"
    Autovification of method calls should be pragmatized, being able to turn it off.
    --
    Reini Urban
  • Ricardo SIGNES at May 7, 2008 at 11:50 am
    * Reini Urban [2008-05-07T06:19:20]
    2008/5/6 Ricardo SIGNES <perl.p5p@rjbs.manxome.org>:
    A truly anemic start would be to write classes with no methods save for
    AUTOLOAD. Unfortunately, AUTOLOAD does not catch universal methods. This
    is worse than just having to write a "can" and "isa." If anything in your
    process loads UNIVERSAL::{moniker,require} or Sub::Install, or any of a
    number of other things that muck with UNIVERSAL, your code will change in
    bizarre ways.
    I would just write something along "no autoload"
    Autovification of method calls should be pragmatized, being able to turn it
    off.
    One of us is confused.

    What I meant was "I can't use AUTOLOAD to autovivify /all/ methods, because it
    will never be able to autovivify methods found in UNIVERSAL."

    It seems like you're suggesting a solution to the opposite problem.

    --
    rjbs
  • Reini Urban at May 7, 2008 at 9:53 pm

    Ricardo SIGNES schrieb:
    * Reini Urban [2008-05-07T06:19:20]
    2008/5/6 Ricardo SIGNES <perl.p5p@rjbs.manxome.org>:
    A truly anemic start would be to write classes with no methods save for
    AUTOLOAD. Unfortunately, AUTOLOAD does not catch universal methods. This
    is worse than just having to write a "can" and "isa." If anything in your
    process loads UNIVERSAL::{moniker,require} or Sub::Install, or any of a
    number of other things that muck with UNIVERSAL, your code will change in
    bizarre ways.
    I would just write something along "no autoload"
    Autovification of method calls should be pragmatized, being able to turn it
    off.
    One of us is confused.

    What I meant was "I can't use AUTOLOAD to autovivify /all/ methods, because it
    will never be able to autovivify methods found in UNIVERSAL."

    It seems like you're suggesting a solution to the opposite problem.
    Not really. A better object system should throw away AUTOLOAD
    and autovification of methods. Just as kurila did.
    Linda W started a thread some time ago about the problems with
    destructivily checking methods inheritance. (can is destructive)
    Not possible with perl5 semantics because of AUTOLOAD.

    So I proposed "no autoload" and on top of that write your Class:Metameta.
    It would let you have a clear distinction between class and object methods.
  • Aristotle Pagaltzis at May 8, 2008 at 12:26 am

    * Reini Urban [2008-05-07 23:55]:
    Linda W started a thread some time ago about the problems
    with destructivily checking methods inheritance. (can is
    destructive)
    No it’s not. It’s taking a reference that is.

    Regards,
    --
    Aristotle Pagaltzis // <http://plasmasturm.org/>

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupperl5-porters @
categoriesperl
postedMay 6, '08 at 3:37p
activeMay 8, '08 at 12:26a
posts13
users5
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase