2

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?

1
  • 2
    b is a hash key, not a method. So to call the sub you need to extract from the hash first like this: print $foo->{b}()."\n"; Commented Aug 13, 2024 at 16:44

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Your print $foo->{b} would just print the reference to the anonymous subroutine, If you wanted to run it, you would want print $foo->{b}->().
Do I still need ` $_[0];` ?
When I do print $foo->{b}(), "\n"; it prints foo but when I do print Dumper($foo->{b}()); I get Undefined subroutine &Foo::Dumper called. Why is that?
You imported Dumper into package main, but the code is executing in package Foo. Put package Foo; and its methods in curlies.
So I would use a sub to access b as a hash key? But the intention was to call a sub ref
2

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 

10 Comments

So I would need to keep my defintion of new for this sub b to work?
You still need an object blessed into Foo. How that object is created is not relevant. new is not special in Perl, other than as a convention.
I appened your snippet and run print $foo->b(1234)."\n"; and it still prints foo. When I did a Dumper($foo) it says: bless( { 'a' => 1, 'b' => sub { "DUMMY" } }, 'Foo' );
Re "print $foo->b(1234)."\n"; and it still prints foo.", Still??? It now prints foo. Before, it was giving you an error. You asked to make it call the anon sub, which prints foo. And you just said that's what it does.
ah you are right, I got confused with @_ expecting it to print out what was there. My bad
|
0

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.