Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Is it legal to create subs in a module?

by Anonymous Monk
on Oct 11, 2001 at 19:18 UTC ( [id://118229]=perlquestion: print w/replies, xml ) Need Help??

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

Hello,

Still working on my module. It works but I'm wondering if I've done something thats not programatically correct. In part of the module it creates subs that return the value the subs name was set to in the object hash. All that really does is make it where instead of getting the value as the following:

$obj->{"blah"};

You can get the value via:

$obj->blah

The subs are created after a validity check via the folowing eval:

eval "sub $action { my \$pkg = shift; return(\$pkg->{\"$action\"}); }";

This all works fine, kinda. In my t/module.t the subs seem to be hanging around even after I undef($obj). This confuses me. I am creating a new object at the start:

$obj = new Object(qw(blah good));

Do some tests, then undef($obj). I attempt to create a new $obj in a manner that should fail but its not failing the way I'm expecting it to.

$obj = new Object(qw(blah reserved));

It should come back and tell me the option reserved is a reserved word. Instead it comes back with the following error/warning:

Subroutine blah redefined at (eval 7) line 1

I thought undef($obj) would clear things up but aparently its not. Why are the first defined subs sticking around?

TIA
TG

Replies are listed 'Best First'.
Re: Is it legal to create subs in a module?
by merlyn (Sage) on Oct 11, 2001 at 19:27 UTC
    First, please don't use string eval for something like:
    eval "sub $action { my \$pkg = shift; return(\$pkg->{\"$action\"}); }" +;
    It's far better instead to compile that code once, plugging in the parts that are variable, using a closure, like:
    { my $action = "whatever"; no strict 'refs'; *{$action} = sub { my $pkg = shift; return $pkg->{$action}; }; }
    There. No nasty runtime eval, meaning no "firing up the compiler" every time you add a method (s-l-o-o-o-o-o-w), nor worries that if $action contains quote-character messiness, you'll get clobbered.

    Second, the class package (where the methods are kept) is not per-object, but shared amongst all objects. So if one object added a "blah" method, that would be seen by all objects.

    Maybe what you want is one of the classless object solutions, like Class::Prototyped by the Monestary's own bikeNomad. That lets you create lightweight classes with methods that are specific to that object. In fact, you can then inherit from that (very Self-like, if you're familiar with Self).

    -- Randal L. Schwartz, Perl hacker

Re: Is it legal to create subs in a module?
by davorg (Chancellor) on Oct 11, 2001 at 19:32 UTC

    Methods are stored at the class level, not at the object level. In Perl terms, when you create a method you are installing a subroutine in the symbol table for your package. Removing an object doesn't do anything to the package's symbol table.

    A better way to do this is using AUTOLOAD like this:

    sub AUTOLOAD { my ($pkg, $attr) = $AUTOLOAD =~ /(.*)::(.*)/; *{$attr} = sub { return $_[0]->{$attr} }; return $_[0]->{$attr}; }

    Although that still doesn't solve your main problem.

    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you don't talk about Perl club."

      Doesn't both your's and lestrrat's answer(s) need to ignore the DESTROY method? Like:
      return if $AUTOLOAD =~ /::DESTROY$/;

        Good point. I'd probably get round that by defining a dummy DESTROY method that does nothing.

        --
        <http://www.dave.org.uk>

        "The first rule of Perl club is you don't talk about Perl club."

      Of course you could be evil and use a blessed coderef as your representation. That coderef could dispatch methods differently for each instance (the instance information being kept in a lexical visible when the closure is created). But you probably can only get away with that if you're Damian (c.f. Object Oriented Perl, Chapter 11, p297-300).

Re: Is it legal to create subs in a module?
by MZSanford (Curate) on Oct 11, 2001 at 19:26 UTC
    If i am reading this correct, what you are trying to do, while possible, is not really a good idea. If you are looking to make $foo->{key} available via $foo->key by making dynamic methods, i suggest taking a look at the AUTOLOAD routine ... as it is made for just such an occasion.
    "They shall not overcome. Whoever told them that the truth shall set them free was obviously and grossly unfamiliar with federal law."
        -- John Ashcroft
Re: Is it legal to create subs in a module?
by dragonchild (Archbishop) on Oct 11, 2001 at 19:26 UTC
    Subroutines are created within the package's namespace. An object is simply an reference that can call subroutines (methods) in that namespace. Doing anything to the object doesn't affect the namespace.

    What you want to do is something like:

    { no strict 'refs' eval "sub $action { my \$pkg = shift; return(\$pkg->{\"$action\"}) +; }" unless defined &{$action}; }
    In fact, you should be doing that anyways. What you have right now won't allow you to create two objects at once or even override the default accessors. :-)

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

Re: Is it legal to create subs in a module?
by lestrrat (Deacon) on Oct 11, 2001 at 19:34 UTC

    Subs are declared as part of the packge, not part of an object.

    If your Object->new() method dynamically creates a sub called foo, then you're in effect declaring Object::foo. This sub is now bound to the package, and therefore will stick around until the end of the execution

    There are several approaches:

    ## autoload sub AUTOLOAD { my $self = shift; ( my $subname = $AUTOLOAD ) =~ s/.*:://; if( $obj->{ $subname } ) { ## this is over simplified, so you may need to do ## other checks... return $self->{ subname }; } else { croak "No such sub"; } }

    If you just want to get/set attributes, I recommend the AUTOLOAD way rather than dynamically declaring subs. There would be no residual subs floating around that way

Re: Is it legal to create subs in a module?
by Anonymous Monk on Oct 15, 2001 at 19:29 UTC
    Thank you for all of your input. The help here is great. TG

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (4)
As of 2024-04-16 18:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found