1

I'm using Moose, maybe it matters, maybe it doesn't.

My object comes in as $event, and I save the args attribute value to a variable:

my $args = $event->args;

That value happens to be a hash, so I do some stuff to the hash, specifically adding a new element:

$$args{id} = 4;

Here's what I don't understand, when I go back to look at my $event object, it has that new hash element saved inside! I set it to a completely different variable, not the object, so why does the object receive it?

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
Ryan
  • 672
  • 1
  • 6
  • 16
  • Better as `$args->{id} = 4` – Borodin Jan 06 '13 at 22:04
  • I'm not clear what difference you expected the assigment to make. If it doesn't modify the object somehow then what is it for? It is rarely a good idea to poke around the contents of an object. You should stick to the official interface as described in the documentation. – Borodin Jan 06 '13 at 22:19

3 Answers3

2

Moose does not matter. $event->args returns you hash refence, so your copy and $event->args points to same hash. When you add a key it will be added, so it visible from both references.

To avoid this, you can copy hash which is returned by args:

my $args = {%{$event->args}};

After copy you getting reference to new hash so $args becomes reference to copy, no other code change required.

Galimov Albert
  • 7,269
  • 1
  • 24
  • 50
2

If you want to get a little bit advanced, instead of doing

has 'args' => (
  is => 'rw',
  isa => 'HashRef',
);

or whatever you normally do, you can do something like

has '_args' => (
  is => 'ro',
  isa => 'HashRef',
  default => sub { +{} },
  traits => ['Hash'],
  handles => {
    args => 'kv', # or args => 'shallow_clone'
    set_arg => 'set',
    get_arg => 'get',
    clear_arg => 'delete',
  },
);

now, the args are still stored in the object as a hashref, but it's stored in a private attribute named _args, and you use other methods to access it, for example my %args = $event->args (if you used kv) or my $args = $event->args (if you used shallow_clone, you get a hashref, but it's still a copy), $event->set_arg("foo" => "bar"); my $value = $event->get_arg("foo") etc. This is strictly optional, and you should skip it if you don't understand it, but it helps you build a more orthogonal interface and hide implementation details from your users.

hobbs
  • 223,387
  • 19
  • 210
  • 288
  • This does make sense, thank you. I always thought setting a new variable with a hashref cloned the hash. – Ryan Jan 07 '13 at 18:42
1

What you get back from $event->args is not a hash, but a hash reference. That is, it's a pointer to a hash which is also pointed to by the args attribute in your object. When you say $$args{id} = 4 (or $args->{id} = 4 which is equivalent) you're changing the value in the hash that $args points to. Since a pointer to that hash is also stored in your object, the change is reflected there as well.

If you want to change the stuff in $args without affecting the object, you can make a copy of the hash:

my %args = %{ $event->args };
friedo
  • 65,762
  • 16
  • 114
  • 184