Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Can I add methods to an existing object?

by pileofrogs (Priest)
on Apr 02, 2009 at 19:44 UTC ( [id://755089]=perlquestion: print w/replies, xml ) Need Help??

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

Is it possible to add methods to an existing object? Would I have to re-bless it into a new class, or is it possible to just whack a code ref on there somehow?

Thanks!

  • Comment on Can I add methods to an existing object?

Replies are listed 'Best First'.
Re: Can I add methods to an existing object?
by ikegami (Patriarch) on Apr 02, 2009 at 20:10 UTC
Re: Can I add methods to an existing object?
by Fletch (Bishop) on Apr 02, 2009 at 20:44 UTC

    What happened when you tried it?

    use strict; package Foo; sub new { my( $c, $v ) = @_; return bless { val => $v }, $c; } sub wubble { print "Wubble: ", shift()->{'val'}, "\n"; }; package main; my $f = Foo->new( "abc" ); $f->wubble; eval { $f->flop; }; if( $@ ) { print "Problem: $@\n"; } eval q{sub Foo::flop { print "Flop: ", scalar reverse( shift()->{'val' +} ), "\n"; }}; eval { $f->flop; }; if( $@ ) { print "Problem: $@\n"; } exit 0; __END__ Wubble: abc Problem: Can't locate object method "flop" via package "Foo" at /tmp/s +quonk line 15. Flop: cba

    (Of course if you're serious then Moose and Class::MOP would be less hacky ways to do it.)

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Can I add methods to an existing object?
by morgon (Priest) on Apr 02, 2009 at 21:04 UTC
    If you can accept that the method is added to the class (and not just to this one instance in the way you can have singleton-methods e.g. in Ruby) this is very simple as methods are just symbol-table entries just like any other sub.

    Here an example that adds a new "bubba" method to a "Hubba"-class after an instance already has been created:

    use strict;
    
    package Hubba;
    
    sub new {
     my($pck)=@_;
    
     bless {}, $pck;
    }
    
    # no bubba-method defined here
    
    package main;
    
    # create new instance
    my $h = new Hubba;
    
    # add entry to symbol-table
    *Hubba::bubba = sub { print "bubba" };
    
    # call new method via old instance
    $h->bubba;
    
    
      You can also declare that as:

      sub Hubba::bubba { print "bubba" }

      which looks more intuitive to me. BTW, is the "Bubba" capitalized in the name of the bubble gum brand?

        This is not quite the same thing.

        Your approach declares the bubba-method at compile-time, my example at run-time.

        You could not use your approach e.g. in a context where the name of the method to be added in not known at compile-time (e.g. is entered by the user).

        And "hubba" and "bubba" are my just my personal preference for generic names that I use where others may use "foo" and "bar" that others prefer - I can't remember where I got that from initially but it has nothing to do with bubble gum :-)

Re: Can I add methods to an existing object?
by roubi (Hermit) on Apr 02, 2009 at 20:33 UTC
    What type of restrictions are you dealing with here? There are various ways to accomplish this, but your post seems to imply that the simplest one (adding the methods to the file describing your object's class) is off-limit. A little more background would help narrow down the amount of hackery required in your case.

      Right, sorry..

      I'm doing some Cat stuff and using Authen::Simple for authentication. My Cat instance has a Log::Dispatch logger which has methods like 'error','warning','debug' etc... Authen::Simple objects can take a logging object too, but it has to provide 'debug','info','warn' and 'error'. Log::Dispatch provides 'warning' but not 'warn'. To work around this, I made my own class which I called Log::Dispatch::Warn, which is a subclass of Log::Dispatch with a 'warn' sub which just calls 'warning'.

      It seems kind of silly to create a whole module just to make an object call $self->warning(@_) if someone calls $object->warn($blah).

        First, I thought of something like this:

        *Log::Dispatch::warn = *Log::Dispatch::warning;

        But I thought, that it doesn't look nice ;) so I changed it to:

        *Log::Dispatch::warn = \&Log::Dispatch::warning;

        But both threw warnings that Log::Dispatch::warn is "used only once: possible typo..."; And then, based upon the answers from morgon and mr_mischief I thought of

        sub Log::Dispatch::warn { my $self = shift; $self->warning(@_); }

        tested with:

        #!/usr/bin/perl -l use strict; use warnings; package foo; sub new { bless {}, shift(); } sub foo { my $self = shift; print "hello @_"; } package main; sub foo::bar { my ( $self ) = shift; $self->foo(@_); } *foo::baz = \&foo::foo; *foo::buzz = *foo::foo; my $o = foo->new(); $o->bar('world'); $o->baz('world'); $o->buzz('world'); __END__
        It'd be interesting to hear from autarch himself why 'warn' wasn't added to the list of valid methods of Log::Dispatch when various other abbreviations like 'err' and 'crit' and 'emer' have been. Maybe he is just waiting to hear from someone like you? :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://755089]
Approved by zwon
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-24 11:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found