hair-tearing perl question
Dec. 20th, 2006 05:49 pm![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
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:
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 saysHASH(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++?
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
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++?
no subject
Date: 2006-12-20 06:24 pm (UTC)Completely untested:
sub footle
{
my ($a,$b,$done) = @_;
my $concat = $a.$b;
if (!exists $done->{$concat})
{
print "footling $a $b";
$done->{$concat} = 1;
}
}
my %isdone = ();
footle("bootle","bumtrinket",\%isdone);
footle("bootle","bumtrinket",\%isdone);
no subject
Date: 2006-12-20 09:43 pm (UTC)$done->{$a}{$b} = 1
to avoid issues where you callfootle("foo", "bar")
and thenfootle("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...
no subject
Date: 2006-12-20 09:46 pm (UTC)no subject
Date: 2006-12-21 12:35 am (UTC)(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)
no subject
Date: 2006-12-20 06:33 pm (UTC)But there's something funny going on, because it *is* possible to pass a hash reference that you update, I've done it frequently I thought.
Maybe it's a syntax problem referring to the reference; I can't find an example where a hash reference is passed in, but when I dig one out of a structure in my working applications I see code like "if (keys(%{$picdb->{DBINFO}}))", that is, %{}.
Possibly using the right function template would help? (if only to make the calling sequence cleaner).
no subject
Date: 2006-12-21 12:45 am (UTC)def wurble
{
my ($a,$b,$c,$done) = @_;
footle($a,$b,$done);
footle($a,$c,$done);
footle($c,$b,$done);
}
and then called
wurble("left","right","middle",%frog)
rather thanwurble("left","right","middle",\%frog)
.Googling on 'perl function template' gives me a rather sophisticated way of generating stereotyped functions of the form
*$fname = sub { print join "*",$fname,@_ }
but that isn't really what I want.
no subject
Date: 2006-12-21 01:15 am (UTC)closure
Date: 2006-12-20 08:37 pm (UTC)Or you could use a closure and do away with the isdone:
which also avoids the minor bug you had if suffixes of A and prefixes of B could get mixed up.
Re: closure
Date: 2006-12-21 12:40 am (UTC)[in my app, $a and $b are element symbols, so I use $a."-".$b as the hash key and the suffix/prefix issue doesn't arise]
Re: closure
Date: 2006-12-21 02:21 am (UTC)("foo-bar", "quux") vs ("foo", "bar-quux").
I'm just succeeding in getting my own head around perl objects (POOP == best programming paradigm name EVAR!), and I just looked through my code to find the single worst line I could find (I'm sure there's more).
my $x_err = $pivot[$i]->{its}[-1]->x_err;
Calling a method of an object which returns a (reference to? I can't remember) array, which is then indexed to get the last element, which is in turn an object, so we call a method to obtain a value from it.