RockyMtn has asked for the wisdom of the Perl Monks concerning the following question:
I'm redoing old cryptic code and found this seemingly useful idiom for casting array refs back to arrays.
fit_data(\@array);
sub fit_data {
my $refCopy=$_[0];
*ydata=$refCopy;
print "array contains: ",join(",",@ydata)," \n";
print "last index is $#ydata \n";
}
but I can't find a way to get this to work under 'strict', even if we excuse the glob part.
As the following 3 versions illustrate, I've tried declaring my @ydata as a lexical, and as a global outside the routine (which I'd like to get away from), but they all have their drawbacks. Is there a way to do this cleanly within a subroutine, and still use strict for your uses of the array?
use strict;
my @valueArr = (1,2,3,4);
fit_data(\@valueArr);
fit_dataLex(\@valueArr);
fit_dataGlobal(\@valueArr);
sub fit_data {
no strict "vars";
my $refCopy=$_[0];
*ydata=$refCopy;
print "array contains: ",join(",",@ydata)," \n";
print "last index is $#ydata \n";
#but you can't use strict on @ydata references
}
#if we define @ydata with my, it's not in the glob table, but strict i
+s happy.
sub fit_dataLex {
use strict;
my @ydata;
my $refCopy=$_[0];
*ydata=$refCopy; #but @ydata not set
print "array contains: ",join(",",@ydata)," \n";
print "last index is $#ydata \n";
}
# if we create @ydata as global, we have to qualify it every time,
# and dirty our global space with 'local' vars.
@main::ydata = (); #to use a typeglob below,
sub fit_dataGlobal {
use strict;
my $refCopy=$_[0];
*ydata=$refCopy;
print "array contains: ",join(",",@main::ydata)," \n";
print "last index is $#main::ydata \n";}
Re: aliasing arrays using typeglob under strict
by BrowserUk (Patriarch) on Feb 08, 2013 at 01:40 UTC
|
sub fit_data {
our @ydata;
local *ydata = shift;
print "array contains: ",join(",",@ydata)," \n";
print "last index is $#ydata \n";
};;
fit_data( [ 1..10 ] );;
array contains: 1,2,3,4,5,6,7,8,9,10
last index is 9
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [Watch: Dir/Any] [d/l] |
Re: aliasing arrays using typeglob under strict
by AnomalousMonk (Archbishop) on Feb 08, 2013 at 03:25 UTC
|
... this seemingly useful idiom for casting array refs back to arrays.
... and for creating global symbols (with the creation points buried in functions) to lie in wait to ambush your sanity during your next 3 AM debug session.
If you're not dealing with module operations (e.g., export of package variables), what would be wrong (or less useful) with using the standard lexical @$array_ref $#$array_ref $array_ref->[$index] @{ $array_ref }[ $n .. $m ] etc. dereferencing operators/operations?
| [reply] [Watch: Dir/Any] [d/l] |
|
and for creating global symbols (with the creation points buried in functions) to lie in wait to ambush your sanity during your next 3 AM debug session.
There is no risk if the globals are localised; and the syntax advantages are clear.
Not using a feature because it involves the temporary use of localise (effectively lexical*) "global variables" is unfounded paranoia.
(*Nothing associated with this usage persists beyond the lexical scope in which the aliasing is performed.)
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [Watch: Dir/Any] |
|
Nothing associated with [the temporary use of localise] persists beyond the lexical scope in which the aliasing is performed.
I disagree. In my understanding, the dynamic scope of a function in respect of package (or global) variables extends to all functions called by the function, in contrast to lexical scope, which is, well, lexical.
So in the example code below, the function G() can exercise "spooky action at a distance" on data localized in the F() function because G() executes within the dynamic scope of F().
One may say that this effect may be avoided by remembering to carefully localize all package variables in all called functions, but this is just the sort of 'care' that one so often forgets to exercise in one's own behalf, to say nothing of all the other stumblebums out there.
IOW, not using global variables is very well-founded paranoia: sometimes those globals really are out to get you! There's a place for globals, gotos, and a host of other 'questionable' programming constructs, but they should always be approached accompanied by a healthy dose of paranoia.
>perl -wMstrict -le
"my @ra = (9, 8, 7, 6);
;;
F(\@ra);
;;
sub F {
our @ydata;
local *ydata = shift;
print qq{pre-G: (@ydata)};
G();
print qq{post-G: (@ydata)};
}
;;
sub G { our @ydata = 'Gaaaahh!'; }
"
pre-G: (9 8 7 6)
post-G: (Gaaaahh!)
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|
Re: aliasing arrays using typeglob under strict
by Anonymous Monk on Feb 08, 2013 at 02:13 UTC
|
#!/usr/bin/perl --
use strict;
use warnings;
ff([ 1..9 ]);
sub ff {
our @ar;
local *ar = shift;
say int @ar
}
| [reply] [Watch: Dir/Any] [d/l] |
Re: aliasing arrays using typeglob under strict
by LanX (Saint) on Feb 08, 2013 at 17:20 UTC
|
To put it in one phrase
In core perl aliasing and other glob-tricks only work with package vars and not lexicals!
Gl*bs are an integral part of the symbol-tabel architecture which aren't available in Lexical Pads!
This is one of the breaks of orthogonality in Perl which itch the most and it has been addressed in Perl6.
Now many workarounds have been offered, but for the sake of clarity I recommend sticking with explicit dereferencing.
For me seeing something like @$a_argument = (1,2,3) somewhere in your code makes it immediately evident that the callers argument is altered, without needing to check how the arguments where passed in the head of the routine. (Otherwise I would recommend to suffix the name of the variable with something like "_alias").
I can hardly imagine occasions where you need to do this more than once, and if you encounter one of these situations, better try one of the other recommended workarounds like our + local or Data::Alias .
| [reply] [Watch: Dir/Any] [d/l] [select] |
Re: aliasing arrays using typeglob under strict
by 7stud (Deacon) on Feb 08, 2013 at 05:09 UTC
|
...and the syntax advantages are clear.
Can you explain that? When I look at the following two functions, I can't see any syntax advantage:
sub fit_data {
our @ydata;
local *ydata = shift;
print "array contains: ",join(",",@ydata)," \n";
print "last index is $#ydata \n";
};;
sub fit_data {
my @ydata = @{shift()};
print "array contains: ",join(",",@ydata)," \n";
print "last index is $#ydata \n";
}
Am I overlooking something?
| [reply] [Watch: Dir/Any] [d/l] |
|
| [reply] [Watch: Dir/Any] |
|
Am I overlooking something?
Yes. You are copying the entire array. What was the point of passing a reference?
That's a very costly operation even for moderately large arrays, just to avoid indirecting through the reference.
But if you can avoid indirect syntax for array and hashes, and avoid copying, and retaining read/write access; all for the cost of naming the argument; all achieved with no action at a distance -- everything is confined to the scope of the subroutine -- then I think that the "syntactic advantages" are clear.
Try re-writing this without aliasing and it will either be much less clear syntactically; or vastly less efficient:
sub mmMxM {
our( @A, @B );
local( *A, *B ) = @_;
my @C = map[0,0,0,0], 0..3;
for my $i ( 0 .. 3 ) {
for my $j ( 0 .. 3 ) {
$C[$i][$j] += $A[$i][$_]*$B[$_][$j] for 0 .. 3;
}
}
return \@C;
}
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [Watch: Dir/Any] [d/l] |
|
Try re-writing this without aliasing and it will either be much less clear syntactically; or vastly less efficient...
BrowserUk operates in an environment in which it is vital to squeeze every last, living computron from any processor, algorithm or function with which he deals, so I am not inclined to dispute his assertion that indirect access is "vastly less efficient".
I would argue with his assertion about clarity. This, of course, is very much a matter of personal taste; I'm not aware of any widely accepted metric for benchmarking 'clarity' – or even for defining its meaning! I would say that the (untested) way I have re-written mmMxM() below is, to my taste, at least as clear as the original. (Again, all issues of performance are entirely neglected. And I don't understand what this thing is doing in the first place... some kind of matrix multiply?)
use constant N => 3;
sub mmMxM {
my ($ar_A, # ref. to array of ...
$ar_B, # ref. to array of ...
) = @_;
my @c = map [ map 0, 0..N ], 0..N; # AoA of zeros
for my $i (0..N) {
for my $j (0..N) {
$c[$i][$j] += $ar_A->[$i][$_] * $ar_B->[$_][$j] for 0..N;
}
}
return \@c;
}
I have, believe me, the utmost respect for BrowserUk, a most subtle and puissant (that's puissant, not pissant!) monk whose programming boots I am not fit to lick clean, but I felt compelled to offer my USD0.02 on the subject of clarity.
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
|
|