Jim
Jim

Reputation: 4425

Trying to use an anonymous object in Perl

I have this script

use strict;
use warnings;
use Data::Dumper;

package Foo;
sub new {
    bless { 'a' => 1, 
            'b' => sub { return "foo" }
    }, $_[0]
};
    
my $foo = Foo->new;
print $foo->b()."\n";

And when I run it I get Can't locate object method "b" via package "Foo" Doesnt this code create an anonymous object so I could call the function b?

Upvotes: 2

Views: 118

Answers (3)

ikegami
ikegami

Reputation: 386541

In Perl, method invocation always involves a package.

$foo is blessed into Foo, so $foo->b calls &Foo::b (or the &b of a package from which Foo inherits).

I have no idea why you think it would call &{ $foo->{ b } }. Objects don't even need to be hashes.

To make b specific to the object, you could add the following to Foo:

sub b { $_[ 0 ]{ b }->( @_ ) }

If you want hide b from stack traces and from caller, you could use

sub b { goto &{ $_[ 0 ]{ b } }; }

Demo:

use v5.14;
use warnings;

{
   package Foo;

   sub new {
      my $class = shift;
      return bless( { @_ }, $class );
   }

   sub b { $_[ 0 ]{ b }->( @_ ) }
}
    
my $foo1 = Foo->new( b => sub { "foo" } );
my $foo2 = Foo->new( b => sub { $_[1] } );

say $foo1->b( 123 );  # foo
say $foo2->b( 123 );  # 123

Upvotes: 2

roger
roger

Reputation: 1

If you want to ceate an anonymous object, with methods from hash keys something like this

    my $obj; $obj = Plack::Util::inline_object(
            b => sub { $obj->{_b} },
            _b => 'foo',
    ));

This will give you $obj->{_b} and $obj->b both returning 'foo'

$obj->{b}() and $obj->{b}->() also work

There are multiple ways to do it, Plack::Util::inline_object is just the one I last used.

Upvotes: 0

Sue D. Nymme
Sue D. Nymme

Reputation: 946

In your code, b is not a method, it's a key of the hashref on which your object is based. If you really want to address it that way, you'd do it this way:

  print $foo->{b}, "\n";

But you (probably) don't want to do that. One of the strengths of object-oriented programming is keeping other parts of your program from reaching into your objects and manipulating them directly. Instead, you (probably) want to create methods for accessing your objects' attributes:

  Package Foo;
  sub new { bless {'a' => 1, 'b' => 2, ...}, $_[0]; }
  sub b { my $self = shift;  return $self->{b}; }

and so on.

Upvotes: 5

Related Questions