Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

why is a 2-argument bless not working in my situation

by eXile (Priest)
on Mar 31, 2004 at 00:55 UTC ( [id://341163]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, this is probably very simple, but my brain is starting to smoke because I just can't find what I'm doing wrong. I want to make Fiets::Cache an inherited class of Cache::Cache (I want to do some extra stuff in the get and set functions), so I wrote this constructor:
package Fiets::Cache; use strict; use warnings; ... sub new { my ($self,$class)=@_; my $cdir = Fiets::getvar('cachedir'); if ($cdir) { use Cache::FileCache; use base qw(Cache::FileCache); $self=Cache::FileCache->new({ 'cache_root' => $cdir, 'default_expires_in' => '4 h' }); } else { use Cache::NullCache; use base qw(Cache::NullCache); $self=Cache::NullCache->new({ 'default_expires_in' => '4 h', }); } bless ($self,$class); return $self; } ... 1;
This code is called from Fiets.pm like this:
use Fiets::Cache; our $cache=Fiets::Cache->new();
Fiets.pm and $Fiets::cache are used in my main-program, and other libraries in the Fiets::-hierarchy.

Now my problem: Calls like $Fiets::cache->get($id) in other libraries will return errors (via an Exception-handler) like:
'Can\'t locate object method "get" via package "main"'
If I change the two-argument bless into bless($self), these errors disappear and in the debugger I can see (with 'm') that my Fiets::Cache indeed has its own new method and a couple of other methods of it's own and inherits a whole bunch of methods for Cache::Cache.

But I still don't know why the two-argument bless will not work for me. This must be something stupid and simple I guess.

PS: 'Fiets' is just a hypothetical name.

Replies are listed 'Best First'.
Re: why is a 2-argument bless not working in my situation
by tedrek (Pilgrim) on Mar 31, 2004 at 01:27 UTC

    Your new method is being called as a class method, therefore the class is the first argument rather than the second. ie, the class is in $self.

    I tried to swear at perl and it compiled!
Re: 2-argument bless not working?!
by runrig (Abbot) on Mar 31, 2004 at 01:27 UTC
    sub new { my ($self,$class)=@_; .... our $cache=Fiets::Cache->new();
    There is no '$self' in the argument list when you call new like that. The assignment in new() should just be:
    my ($class) = @_; # or # my $class = shift;
    And your use of base is um, just wrong. 'use base' is meant to be set at a package level, and when you use it, you don't need the 'use *package*' line. Is your cachedir set once per program, and you want to inherit from Cache::FileCache or Cache::NullCache based on it per program run, or can it change per instance of an object? I'm not going to guess at what you want there.
        And your use of base is um, just wrong. 'use base' is meant to be set at a package level, and when you use it, you don't need the 'use *package*' line.
      I know 'use base' does an implicit 'require', but sometimes ...
        Is your cachedir set once per program, and you want to inherit from Cache::FileCache or Cache::NullCache based on it per program run, or can it change per instance of an object? I'm not going to guess at what you want there.
      That part of the program is working fine, the 'getvar' function checks %ENV and a config-file for clues on what to use. The whole program just uses 1 instance of Fiets::Cache.

      Thanks a lot, I totally missed the $self there!

        Are you sure you're inheritance chain is being set up properly? use and base are compile-time directives, which means that it doesn't matter where they appear in your code, they'll be executed before your code runs. If it's running as expected, that is, you're able to find the inherited methods when you call them on an instance of your subclass, then I would think you've got some multiple inheritance going on. If you truly want those to be set at runtime, I'd use require and manually adjust the @ISA array.


        "The dead do not recognize context" -- Kai, Lexx
Re: why is a 2-argument bless not working in my situation
by Vautrin (Hermit) on Mar 31, 2004 at 04:31 UTC

    All subroutines (or functions or methods or whatever you were taught to call them in CS101) in perl return a value. You can explicitely return a value by using a return statement, or, the last line is returned. For instance, in the function:

    use strict; use warnings; sub foo { 1; } print foo, "\n";

    You would see an output of 1. Now, you never explicitely returned a value of 1, but because it was the last thing on the line, Perl tried to do what you meant by returning 1. However, Perl is not psychic. So, when you see most constructors ending with:

    bless $self, $class;

    $self is not modified. An object is created when bless is evaluated. The following would do the same thing:

    my $object = bless $self, $class; return $object;

    Consult perldoc bless for more information. So, this:

    bless ($self,$class); return $self;

    should read:

    return bless ($self, $class);

    Also, note that the first element of @_ is the class name, not the second. So:

    my ($self,$class)=@_;

    Should really be the other way around, i.e.:

    my ($class, $self) = @_; # and add a check that we're not copying # for good measure die ("This isn't a copy constructor") if (ref $class);

    And unless you know what you're doing, you shouldn't use anything but a hashref for $self. I think you might want to google for @ISA and read up a little bit on inheritance.


    Want to support the EFF and FSF by buying cool stuff? Click here.
      However, Perl is not psychic. So, when you see most constructors ending with:   bless $self, $class; $self is not modified.
      This is wrong, $self is modified. Try e.g. this:
      sub foo { my $self = {}; bless $self, 'Bar'; return $self; } print "isa Bar.\n" if foo()->isa('Bar');

      -- Hofmator

Re: 2-argument bless not working?!
by Sandy (Curate) on Mar 31, 2004 at 01:53 UTC
    Hi

    I'm no perl expert, so I'm guessing here. Is your definition of $class correct? You don't seem to be passing it as an argument of $cache=Fiets::Cache->new();

    In other words, shouldn't class be defined as... $class=ref($self) ??

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (3)
As of 2024-04-20 01:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found