pem@frankland-river.aaii.oz.au (Paul E. Maisano) (03/17/90)
A short while ago I posted a request to see if anyone could think of a way I could generate a reference to a particular index of an array. For scalars it is easy; I have used code like the following to parse command line args. The effect is: 'prog -p x y -u 1 2 -p z' results in $pvar == 'x y z ', $uvar == '1 2 ' while ($_ = shift) { /^-p$/ && (*vptr = *pvar, next); /^-u$/ && (*vptr = *uvar, next); $vptr .= "$_ "; } Anyway, if I have an array, say @ary = (1, 2, 3) I want to be able to get a reference to an element of that array, so that I can manipulate it independently of the array. Randal mentioned that a foreach might work as in (something like): foreach $x ($ary[1]) { # manipulate x and modify the array } The foreach will only have this effect when an actual array is passed to the foreach. So you can't really use this method. I mentioned that a grep would work as in the following: grep( do { # manipulate $_ and modify the array }, $ary[1] ); This has the draw back of not letting you name the variable to something meaningful. So in my search for neatness (or any kludge that would work) I came up with the following: grep(*vptr = *_, $ary[1]) # manipulate $vptr and modify the array It makes sense when you think about it. `_' contains the symbol table entry for the element of the array which we then assign to `vptr'. (Ok, ok, so I peeked at the source :-) Now I am content and can sleep again at nights. But I am too tired to work out how to generate "Just Another Perl Hacker," using it. Randal ? :-) Here's a test fragment: #!/usr/local/bin/perl @ary = (1, 2, 3); grep(*vptr = *_, $ary[1]); print "@ary\n"; # => 1 2 3 $vptr++; print "@ary\n"; # => 1 3 3 ------------------ Paul E. Maisano Australian Artificial Intelligence Institute 1 Grattan St. Carlton, Vic. 3053, Australia Ph: +613 663-7922 Fax: +613 663-7937 Email: pem@aaii.oz.au UUCP: {uunet,mcsun,ukc,nttlab}!munnari!aaii.oz.au!pem
merlyn@iwarp.intel.com (Randal Schwartz) (03/18/90)
In article <1361@frankland-river.aaii.oz.au>, pem@frankland-river (Paul E. Maisano) writes: | So in my search for neatness (or any kludge that would work) I came up | with the following: | | grep(*vptr = *_, $ary[1]) | # manipulate $vptr and modify the array [...] | Now I am content and can sleep again at nights. | But I am too tired to work out how to generate "Just Another Perl Hacker," | using it. Randal ? :-) Something like this? @ARGV=split(//,'Just another Perl hacker,');push(@x,'')while@x<@ARGV; for$x($[..$#x){grep(*y=*_,$x[$x]);$y=shift;}print@x; (Okay, so it's pretty simplistic...) But it'd be much easier to do: @ARGV=split(//,'Just another Perl hacker,');push(@x,'')while@x<@ARGV; for$y(@x){$y=shift;}print@x; So I still don't know why you want to alias an element like that. :-( By the way, I tried to preextend the array with $#x=$#ARGV, and it didn't work. Why not? print "Just another Perl hacker,"; # to make larry's code happy :-) -- /=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\ | on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III | | merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn | \=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/
pem@frankland-river.aaii.oz.au (Paul E. Maisano) (03/18/90)
In article <1990Mar17.183039.21097@iwarp.intel.com>, merlyn@iwarp.intel.com (Randal Schwartz) writes: > > So I still don't know why you want to alias an element like that. :-( This method probably does not buy you anything that you can't do with associative arrays or using eval and coding things a little differently. I can only give you the reason I was originally looking for a technique like this. Say I have an array of buffers, @current_buffer indexed by $current_line and I want to use it in a subroutine. I don't think it would be uncommon to see something like the following at the start: sub handle_input { local($buf) = $current_buffer[$current_line]; ... From now on I can use $buf instead of the (more informative) but extremely verbose $current_buffer[$current_line]. This is fine and good, everything works well. I have about 5 to 10 references to $buf in my subroutine which I think is easier to read than the alternative. But as soon as realize that I need to start modifying the buffer it stops working since $buf is only a copy. This is not drastic. I can either go back to using the verbose form everywhere or simply copy $buf back into the real buffer before every place I return from the subroutine. The problem seemed to me that I was using local in a different way than was intended. I was trying to use it as an aliasing mechanism which it is not. Now I can say local(*buf) = &ref($current_buffer[$current_line)]; to get the effect I was trying to achieve. For anyone interested &ref can be defined as follows: sub ref { local($tmp); grep($tmp = *_, $_[0]); $tmp; } This routine could be made more general by returning an array of references for each argument. Ie. you could write, local(*x, *y, *z) = &ref($x[1], $y[0], $z[2]); You could even set things up so that two arrays share elements!! I'd better stop right here.. I feel a madness coming on :-) ------------------ Paul E. Maisano Australian Artificial Intelligence Institute 1 Grattan St. Carlton, Vic. 3053, Australia Ph: +613 663-7922 Fax: +613 663-7937 Email: pem@aaii.oz.au UUCP: {uunet,mcsun,ukc,nttlab}!munnari!aaii.oz.au!pem
pem@frankland-river.aaii.oz.au (Paul E. Maisano) (03/19/90)
In article <1362@frankland-river.aaii.oz.au>, I (Paul E. Maisano) write: > For anyone interested &ref can be defined as follows: > sub ref { > local($tmp); > grep($tmp = *_, $_[0]); > $tmp; > } > This routine could be made more general by returning an array of > references for each argument. Ie. you could write, > local(*x, *y, *z) = &ref($x[1], $y[0], $z[2]); The generalized version is: sub ref { local(@stab); grep(push(@stab,*_),@_); # kludge to get at symtab entries wantarray ? @stab : $stab[0]; # contains the binary symtab data } > You could even set things up so that two arrays share elements!! Ignore that. As far as I can tell there is no way whatsoever in the current version of perl to make an array element reference something else. I agree that it's probably not of any real use anyway. The reason I think it is impossible, is that the only way you can make something reference another symbol in perl is to use the type globbing syntax. And you aren't allowed to do "*LVALUE = ..." only "*NAME = ...". In other words, you can't name an array element; only the array. BTW, I would also like to see gethostname (and some version of timelocal) in perl. [But I've already voted for these so it doesn't count, right!? :-] ------------------ Paul E. Maisano Australian Artificial Intelligence Institute 1 Grattan St. Carlton, Vic. 3053, Australia Ph: +613 663-7922 Fax: +613 663-7937 Email: pem@aaii.oz.au UUCP: {uunet,mcsun,ukc,nttlab}!munnari!aaii.oz.au!pem