nck
nck

Reputation: 2221

Is instantiating a hash in a function inefficient in perl?

Is there any difference in doing the following, efficiency, bad practice...?

(In a context of bigger hashes and sending them through many functions)

sub function {
  my ($self, $hash_ref) = @_;
  my %hash = %{$hash_ref};
  print $hash{$key};
  return;
}

Compared to:

sub function {
  my ($self, $hash_ref) = @_;
  print $hash_ref->{$key};
  return;
}

Upvotes: 1

Views: 131

Answers (3)

zdim
zdim

Reputation: 66901

The first version of the sub creates a local copy of the data structure which reference is passed to it. As such it is far less efficient, of course.

There is one legitimate reason for this: to make sure the data in the caller isn't changed. That local %hash can be changed in the sub as needed or convenient and the data in the calling code is not affected. This way the data in the caller is also protected against accidental changes.

Another reason why a local copy of data is done, in particular with deeper data structures, is to avoid long chains of dereferencing and thus simplify code; so parts of deep hierarchies may be copied for simpler access. Then this is merely for (presumed) programming convenience.

So in the shown example there'd be absolutely no reason to make a local copy. However, presumably the question is about subs where more work is done and then what's best depends on details.

Upvotes: 2

ikegami
ikegami

Reputation: 385915

Let's say %$hash_ref contains N elements.

The first snippet does the following in addition to what the second snippet does:

  • Creates N scalars. (Can involve multiple memory allocations each.)
  • Adds N*2 scalars to the stack. (Cheap.)
  • Creates a hash. (More memory allocations...)
  • Adds N elements to a hash. (More memory allocations...)

The second snippet does the following in addition to what the first snippet does:

  • [Nothing. It's a complete subset of the first snippet]

The first snippet is therefore far less efficient than the second. It also more complicated by virtue of having extra code. The complete lack of benefit and the numerous costs dictate that one should avoid the pattern used in the first snippet.

Upvotes: 2

k-mx
k-mx

Reputation: 687

1st snippet is silly. But it's convenient practice to emulate named arguments:

sub function {
   my ($self, %params ) = @_;
   ...
} 

So, pass arrays/hashes by reference, creation of new (especially big) hash will be much slower. But there is nothing bad in "named arguments" hack.

And did you now that there exist key/value slice (v5.20+ only)? You can copy part of hash easily this way: my %foo = ( one => 1, two => 2, three => 3, four => 4); my %bar = %foo{'one', 'four'};

More information in perldoc perldata

Upvotes: 2

Related Questions