CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
Dereference an array

 



Olive
New User

Oct 14, 2017, 2:27 AM

Post #1 of 9 (2258 views)
Dereference an array Can't Post

I am new to Perl. I am trying to dereference an array. According to what I have read, I should do something like that:


Code
my $a = ["a","b","c","d"]; 
my @b = @$a;

$b[1] = "hello";

print $a->[1];
print "\n";

print $b[1];
print "\n";


But this sample code print

Code
b 
hello

Here @b is a copy of the array referenced by $a. What I want is to have a variable @b that contain the actual array, not a copy of it. Something like b=*a in C/C++. How can I have this?


BillKSmith
Veteran

Oct 14, 2017, 7:06 AM

Post #2 of 9 (2250 views)
Re: [Olive] Dereference an array [In reply to] Can't Post

In your code, $a is a reference to an "anonymous array". There is no way to assign a name to such an array. You can accomplish what you want by defining @b as an array and $c as a reference to it. Note: You must use the backslash to create the reference. ([@b] would create a reference to an anonymous copy of @b)


Code
C:\Users\Bill\forums\guru>type olive.pl 
use strict;
use warnings;
my @b = qw(a b c d);
my $a = \@b;

$b[1] = "hello";

print $a->[1];
print "\n";

print $b[1];
print "\n";

C:\Users\Bill\forums\guru>perl olive.pl
hello
hello


For future reference: It is poor practice to use a and/or b as variable names because they sometimes have special meaning in perl (sort).
Good Luck,
Bill


Olive
New User

Oct 14, 2017, 9:31 AM

Post #3 of 9 (2244 views)
Re: [BillKSmith] Dereference an array [In reply to] Can't Post

Thanks. I knew that it was possible to define an array and after that taking a reference to it. But there is apparently no possibility to do the other way around. My example was only a small test to exemplify my question. You might have the reference because you get it as a parameter to a subroutine and, naively, it would have been convenient to have a name for the object referenced by the parameter inside the subroutine, which would avoid the need to use the dereference operator (->) everywhere.

Another question, closely related but not exactly the same if I put


Code
my @list = ("a","b","c","d"); 
my @newlist = @list;
$newlist[1]="hello";
print $list[1];
print "\n";

Then I get "b". Once again a copy of the array is made. It seems that a new copy is made each time you assign something to a new name. Coming from Python, I would be tempted to use references only (in python, everything is a reference) to avoid unexpected copies. But maybe this is my python background...


(This post was edited by Olive on Oct 14, 2017, 9:32 AM)


BillKSmith
Veteran

Oct 14, 2017, 11:34 AM

Post #4 of 9 (2240 views)
Re: [Olive] Dereference an array [In reply to] Can't Post

Perl assignment and argument passing is almost identical to 'C'. You have correctly guessed that it is not possible to assign a name to the thing referred to by a reference.

Your second question really asks if it is possible to create an alias name for a variable. In general this also is impossible. There is one exception. The use of typeglobs makes it possible to create an alias of a package variable. This is an advanced technique which I will not explain.

It is usually a bad practice for a subroutine to modify its arguments. (All results should be returned by the 'return' statement.) Working with a copy of the arguments prevents doing this by accident.

There is a related issue which you may have overlooked. The loop variable in a foreach loop is not exactly what you think. Read the "Foreach Loops" section of perlsyn
Good Luck,
Bill


Olive
New User

Oct 14, 2017, 3:20 PM

Post #5 of 9 (2234 views)
Re: [BillKSmith] Dereference an array [In reply to] Can't Post

Having read the definition of typeglobs you mention, it seems that it can accomplish exactly what I originally asked:


Code
my $a = ["a","b","c","d"];  
*b = $a;

$b[1] = "hello";

print $a->[1];
print "\n";

print $b[1];
print "\n";


both print hello. Is it bad practice? Is it something that I have overlooked. As for the subroutine, I had more in mind avoiding unnecessary extra copies than modifying the arguments. Anyway, in Python, you can do "list.sort()" that sort the list in place. Would it be bad practise to make something similar in perl? There are functions (push) that I think add elements to an existing array.


(This post was edited by Olive on Oct 14, 2017, 3:28 PM)


BillKSmith
Veteran

Oct 14, 2017, 9:10 PM

Post #6 of 9 (2223 views)
Re: [Olive] Dereference an array [In reply to] Can't Post

I believe that regardless of the language that we use, our first objective should be to write code that is easy to debug and maintain. Tricks to optimize speed and/or memory usage should be used only when necessary, and then only on code that profile has identified as a problem area.

Your clever use of typeglobs fails this test on two counts. The first is that it only works with package variables. Problems with properly scoped lexical variables are easier to debug because the problems must be within the scope of that variable. The other problem is that few perl programmers could understand it. (I doubt that you will six months from now. I am quite sure that I will not be able to.)

If you can justify writing your own sort, perl has all the array functions that you would need. The function 'splice' is the Swiss-army-knife of array manipulation. The functions 'push' and 'unshift' are special cases of 'splice'.
Good Luck,
Bill


Olive
New User

Oct 15, 2017, 1:18 AM

Post #7 of 9 (2221 views)
Re: [BillKSmith] Dereference an array [In reply to] Can't Post

Thanks. I indeed discovered that typeglob don't work with lexical scoping variables ("my" variables). However, you can apparently make a typeglob "local". As the "my" variables are the normal way to use a variable, it does not seems indeed a very good idea to use this trick.


FishMonger
Veteran / Moderator

Oct 15, 2017, 9:29 AM

Post #8 of 9 (2214 views)
Re: [Olive] Dereference an array [In reply to] Can't Post

You've mentioned the use of subroutines, but none of your code snippets use subs and you don't give a clear description of how you're using them.


Quote
... would avoid the need to use the dereference operator (->) everywhere

Why do you think you would need to use the -> operator everywhere? Just dereference the passed array ref once at the start of the sub and be done with it.


Code
use 5.010; 
use warnings;
use strict;
use Data::Dumper;

my @letters = ("a","b","c","d");
@letters = letter2word(\@letters);
say Dumper \@letters;

sub letter2word {
my @letters = @{ $_[0] };
$letters[1] = 'hello';
return @letters;
}


If your goal is to not make a copy of the array or use -> to dereference, then do something like this:

Code
use 5.010; 
use warnings;
use strict;
use Data::Dumper;

my @letters = ("a","b","c","d");
@letters = letter2word(@letters);
say Dumper \@letters;

sub letter2word {
$_[1] = 'hello';
return @_;
}


If your goal is to use OO dot notation for method calls, you're not going to get that with perl 5, but you do get that with perl 6. I haven't starting working with perl 6 yet so I can't give an example, but there are plenty out there on youetube (look for Larry's YAPC talks). In his talks he often takes a perl 5 script and converts it step-by-step into perl 6.

Finally, as Bill already pointed out, DON'T use $a or $b (even in code snippet examples) outside of sort routines.


(This post was edited by FishMonger on Oct 15, 2017, 9:34 AM)


FishMonger
Veteran / Moderator

Oct 15, 2017, 10:12 AM

Post #9 of 9 (2208 views)
Re: [FishMonger] Dereference an array [In reply to] Can't Post

I left out one other example. If you want a named var for the passed-in array ref, then you can use subroutine signatures, but you then would still need to use -> to dereference.

Code
use v5.20; 
use feature qw(signatures);
no warnings qw(experimental::signatures);
use Data::Dumper;

my $letters = ["a","b","c","d"];
$letters = letter2word($letters);
say Dumper $letters;

sub letter2word ($letter) {
$letter->[1] = 'hello';
return $letter;
}


This signature also works, which surprised me.

Code
use v5.20; 
use feature qw(signatures);
no warnings qw(experimental::signatures);
use Data::Dumper;

my @letters = ("a","b","c","d");
@letters = letter2word(@letters);
say Dumper \@letters;

sub letter2word (@letter) {
$letter[1] = 'hello';
return @letter;
}



(This post was edited by FishMonger on Oct 15, 2017, 10:19 AM)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives