Mike
Mike

Reputation: 60771

Perl, "closure" using Hash

I would like to have a subroutine as a member of a hash which is able to have access to other hash members.

For example

sub setup {
  %a = (
   txt => "hello world",
   print_hello => sub {
    print ${txt};
  })
return %a
}

my %obj = setup();
$obj{print_hello};

Ideally this would output "hello world"

EDIT

Sorry, I failed to specify one requirement

I should be able to do

$obj{txt} = "goodbye";

and then $obj{print_hello} should output goodbye

Upvotes: 3

Views: 601

Answers (3)

Oesor
Oesor

Reputation: 6642

Close:

sub setup {
  my %a = (
   txt => "hello world",
   print_hello => sub {
    print $a{txt};
  });
  return %a;
}

my %obj = setup();
$obj{print_hello}->();

Upvotes: 0

FMc
FMc

Reputation: 42411

If you want the calling code to be able to modify the message in the hash, you need to return the hash by reference. This does what you asked for:

use strict;
use warnings;

sub self_expressing_hash {
    my %h;
    %h = (
        msg              => "hello",
        express_yourself => sub { print $h{msg}, "\n" },
    );
    return \%h;
}

my $h = self_expressing_hash();
$h->{express_yourself}->();

$h->{msg} = 'goodbye';
$h->{express_yourself}->();

However, it's a bizarre concoction -- essentially, a data structure that contains some built-in behavior. Sounds a like an object to me. Perhaps you should look into an O-O approach for your project.

Upvotes: 7

friedo
friedo

Reputation: 66968

This will work:

sub setup { 
    my %a = ( txt => "hello world" );
    $a{print_hello} = sub { print $a{txt} };
    return %a;
}

my %obj = setup();
$obj{print_hello}->();

Upvotes: 2

Related Questions