fivemack: (spiky)
Tom Womack ([personal profile] fivemack) wrote2006-12-20 05:49 pm
Entry tags:

hair-tearing perl question

What I want: a subroutine footle such that, if you call footle(a,b) twice with the same a,b, it does nothing the second time

What I did:
use strict;
sub footle
{
  my ($a,$b,%done) = @_;
  my $concat = $a.$b;
  if ($done{$concat} == 0)
  {
    print "footling $a $b";
    $done{$concat} = 1;
  }
}

my %isdone = ();

footle("bootle","bumtrinket",%isdone);
footle("bootle","bumtrinket",%isdone);

But this doesn't work because parameters are passed by value.

But if I call as footle("bootle","bumtrinket",\%isdone), which passes isdone by reference, it still does the footling twice.

Even if I put $_[2]=%done before the end of the subroutine, it still does the footling twice.

And if I put print join "*",(keys %done); at the start of the subroutine, it says HASH(0x8188110)footling bootle bumtrinket

So how do I really pass the parameter by reference, as if I'd said void footle(int a, int b, set<string>& done) in C++?
diffrentcolours: (Default)

[personal profile] diffrentcolours 2006-12-20 09:43 pm (UTC)(link)
What he said, though I'd use $done->{$a}{$b} = 1 to avoid issues where you call footle("foo", "bar") and then footle("fo", "obar").

There is also a Perl module which lets you mark a function as cacheable, which means that when it is called a second time with the same parameters, it returns the result from the first call without recalculating. However, the name excapes me at the moment...
diffrentcolours: (Default)

[personal profile] diffrentcolours 2006-12-20 09:46 pm (UTC)(link)
Ah, it's Memoize.pm. I knew it began with an M.

[identity profile] fivemack.livejournal.com 2006-12-21 12:35 am (UTC)(link)
That seems slightly the wrong way to look at this problem; somehow I think of memoisation as an optimisation for functions without side-effects, I wouldn't expect a memoisation module to guarantee that a function which did have side-effects caused those side-effects precisely once.

(eg I would view as totally sensible an implementation of Memoize.pm which used a small LRU cache of results, and recomputed if the input you gave it wasn't in the cache either because it had never been there or because it had dropped out; this wouldn't work in my case)