Need help passing arrays by reference pls.

Discussion in 'Perl Misc' started by G Klinedinst, Feb 6, 2004.

  1. G Klinedinst

    G Klinedinst Guest

    Hi all. I have a question I have been pulling my hair out all day
    over. Can someone tell me what is happening in the following code. The
    first print statements create the results I expect. The subroutines
    statments print arrays with 1 element but not data in [0]. What gives?
    I am passing by reference and then dereferencing in the sub. Can you
    point me towards what I am missing? I have looked at the perlfaqs and
    read the perldocs on references but it I can't find what I am looking
    for. It could also be my sleep deprived mind is seeing it but not
    grokking it. TIA.

    -Greg

    ***********CODE****************
    #!/usr/local/bin/perl

    use strict;
    use warnings;

    my @arr1;
    my @arr2;

    $arr1[0] = 1;

    print( $arr1[0] . ":" . scalar( @arr1 ) . "\n" );
    print( $arr2[0] . ":" . scalar( @arr2 ) . "\n" );
    print( "\n\n" );

    test( \@arr1, \@arr2 );

    sub test
    {
    my @subArr1 = @$_[0];
    my @subArr2 = @$_[1];

    print( $subArr1[0] . ":" . scalar( @subArr1 ) . "\n" );
    print( $subArr2[0] . ":" . scalar( @subArr2 ) . "\n" );
    }
    **************/CODE***********

    **************OUTPUT*********
    1:1
    Use of uninitialized value in concatenation (.) or string at
    ../arrays.pl
    line 12.
    :0


    Use of uninitialized value in concatenation (.) or string at
    ../arrays.pl
    line 22.
    :1
    Use of uninitialized value in concatenation (.) or string at
    ../arrays.pl
    line 23.
    :1
    *************/OUTPUT**********
     
    G Klinedinst, Feb 6, 2004
    #1
    1. Advertising

  2. In article <>,
    G Klinedinst <> wrote:
    :Hi all. I have a question I have been pulling my hair out all day
    :eek:ver. Can someone tell me what is happening in the following code.

    :test( \@arr1, \@arr2 );

    :sub test
    :{
    : my @subArr1 = @$_[0];
    : my @subArr2 = @$_[1];

    Looks like you have a precidence problem. @$_[0] is {@{$_}}[0]
    Your code will work if you use

    my @subArr1 = @{$_[0]};
    my @subArr2 = @{$_[1]};


    I would, though, recommend using prototypes and declaring sub test
    before it is used:

    sub test( \@\@ ) {
    my @subArr1 = @{$_[0]};
    my @subArr2 = @{$_[1]};
    # ...
    }

    test @arr1, @arr2;


    Notice there that you do NOT explicitly \ the arrays as you pass them in.


    Personally, I wouldn't take a copy of the array in the sub unless
    I had a reason to. I would use something akin to

    sub test( \@\@ ) {
    my ($subArr1_ref, $subArr2_ref) = @_;
    print $subArr1_ref->[0] . ':' . scalar( @$subArr1_ref ) . "\n";
    print $subArr2_ref->[0] . ':' . scalar( @$subArr2_ref ) . "\n";
    }
    --
    "There are three kinds of lies: lies, damn lies, and statistics."
    -- not Twain, perhaps Disraeli, first quoted by Leonard Courtney
     
    Walter Roberson, Feb 6, 2004
    #2
    1. Advertising

  3. (G Klinedinst) wrote in
    news::

    > Hi all. I have a question I have been pulling my hair out all day
    > over. Can someone tell me what is happening in the following code. The
    > first print statements create the results I expect. The subroutines
    > statments print arrays with 1 element but not data in [0]. What gives?
    > I am passing by reference and then dereferencing in the sub. Can you
    > point me towards what I am missing? I have looked at the perlfaqs and
    > read the perldocs on references but it I can't find what I am looking
    > for. It could also be my sleep deprived mind is seeing it but not
    > grokking it. TIA.
    >
    > -Greg
    >
    > ***********CODE****************
    > #!/usr/local/bin/perl
    >
    > use strict;
    > use warnings;
    >
    > my @arr1;
    > my @arr2;
    >
    > $arr1[0] = 1;
    >
    > print( $arr1[0] . ":" . scalar( @arr1 ) . "\n" );
    > print( $arr2[0] . ":" . scalar( @arr2 ) . "\n" );
    > print( "\n\n" );
    >
    > test( \@arr1, \@arr2 );
    >
    > sub test
    > {
    > my @subArr1 = @$_[0];
    > my @subArr2 = @$_[1];


    Life would be much easier if you did:

    #! perl

    use strict;
    use warnings;

    my @arr1 = (1, 2, 3);
    my @arr2 = (4, 5, 6);

    $arr1[0] = 1;

    print $arr1[0], ':', scalar @arr1, "\n" ;
    print $arr2[0], ':', scalar @arr2, "\n" ;

    # You should avoid the unnecessary concatenations you had in your code.

    print "\n\n" ;

    test(\@arr1, \@arr2);

    sub test {
    my ($subArr1, $subArr2) = @_;

    print $subArr1->[0], ':', scalar @{$subArr1}, "\n" ;
    print $subArr2->[0], ':', scalar @{$subArr2}, "\n" ;
    }

    --
    A. Sinan Unur
    (reverse each component for email address)
     
    A. Sinan Unur, Feb 6, 2004
    #3
  4. G Klinedinst

    G Klinedinst Guest

    -cnrc.gc.ca (Walter Roberson) wrote in message news:

    > Looks like you have a precidence problem. @$_[0] is {@{$_}}[0]
    > Your code will work if you use
    >
    > my @subArr1 = @{$_[0]};
    > my @subArr2 = @{$_[1]};


    Thanks, that worked perfectly. I see what I was doing now.

    > I would, though, recommend using prototypes and declaring sub test
    > before it is used:
    >
    > sub test( \@\@ ) {
    > my @subArr1 = @{$_[0]};
    > my @subArr2 = @{$_[1]};
    > # ...
    > }
    >
    > test @arr1, @arr2;
    >
    > Notice there that you do NOT explicitly \ the arrays as you pass them in.


    Yep, I am just not sure why. I will need to study the docs this
    weekend and figure out what you are doing here.


    > Personally, I wouldn't take a copy of the array in the sub unless
    > I had a reason to. I would use something akin to
    >
    > sub test( \@\@ ) {
    > my ($subArr1_ref, $subArr2_ref) = @_;
    > print $subArr1_ref->[0] . ':' . scalar( @$subArr1_ref ) . "\n";
    > print $subArr2_ref->[0] . ':' . scalar( @$subArr2_ref ) . "\n";
    > }


    Makes sense. The reason I am making a local copy is that I am going to
    be iterating through them(using a for loop). With your syntax I'm not
    sure how I would go about that. For example I will be doing something
    like this:

    for my $a ( @subArr1 ) {
    print $a;
    }

    If I can figure out how to do that using the references, like you are
    using I will do that otherwise I will have to make a local copy.
    Thanks again.


    -Greg
     
    G Klinedinst, Feb 6, 2004
    #4
  5. In article <>,
    G Klinedinst <> wrote:
    :Makes sense. The reason I am making a local copy is that I am going to
    :be iterating through them(using a for loop). With your syntax I'm not
    :sure how I would go about that. For example I will be doing something
    :like this:

    :for my $a ( @subArr1 ) {
    : print $a;
    :}

    :If I can figure out how to do that using the references, like you are
    :using I will do that otherwise I will have to make a local copy.

    print $_ foreach @$subArr1_ref

    Similarily,

    print "$_: $hash_ref->{$_}\n" foreach (keys %$hash_ref);

    print $$scalar_ref, "\n"
    --
    Warning: potentially contains traces of nuts.
     
    Walter Roberson, Feb 6, 2004
    #5
  6. G Klinedinst

    G Klinedinst Guest

    > Life would be much easier if you did:
    >
    > #! perl
    >
    > use strict;
    > use warnings;
    >
    > my @arr1 = (1, 2, 3);
    > my @arr2 = (4, 5, 6);
    >
    > $arr1[0] = 1;
    >
    > print $arr1[0], ':', scalar @arr1, "\n" ;
    > print $arr2[0], ':', scalar @arr2, "\n" ;
    >


    Unfortunately the arrays hold an index to another array, which
    basically tells which input fields were filled out, so some of the
    arrays are going to be empty(due to the user not entering any data at
    that position).


    > # You should avoid the unnecessary concatenations you had in your code.
    >
    > print "\n\n" ;
    >
    > test(\@arr1, \@arr2);
    >
    > sub test {
    > my ($subArr1, $subArr2) = @_;
    >
    > print $subArr1->[0], ':', scalar @{$subArr1}, "\n" ;
    > print $subArr2->[0], ':', scalar @{$subArr2}, "\n" ;
    > }


    Why is that? Are the commas implemented faster, or just for
    readability? Just curious. It's a habit I picked up from Java so now
    even my Perl code looks like that. It's hard to break coding habits
    once you get into them. Thanks for your help, and I hope things are
    starting to warm up there in Ithaca for you.

    -Greg
     
    G Klinedinst, Feb 6, 2004
    #6
  7. In article <>,
    G Klinedinst <> wrote:
    :> # You should avoid the unnecessary concatenations you had in your code.

    :Why is that? Are the commas implemented faster, or just for
    :readability?

    Commas in print's are converted into concatenation internally, so both
    have the same execution speed.

    Sometimes, though, if you use concatenation, you can end up
    with unexpected results because of precidence issues. Just a couple
    of days ago, I had something of the form

    print Operation Argument . Somestring

    and Operation was being applied to Argument . Somestring
    instead of Operation Argument being computed and Somestring being
    concatenated on the end. My fault for not thinking about precidences.
    Changing to , instead of . fixed the code.
    --
    Will you ask your master if he wants to join my court at Camelot?!
     
    Walter Roberson, Feb 6, 2004
    #7
  8. G Klinedinst <> wrote:

    > for my $a ( @subArr1 ) {


    > If I can figure out how to do that using the references, like you are
    > using I will do that



    Apply "Use Rule 1" from perlreftut.pod:

    for my $a ( @subArr1 ) { # pretend it is a regular array

    for my $a ( @{ } ) { # replace the array _name_ with a block...

    for my $a ( @{ $subArr1_ref } ) { # ... that returns a ref to an array

    (and in this case you can drop the block's curlies)


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Feb 6, 2004
    #8
  9. G Klinedinst

    ko Guest

    Walter Roberson wrote:

    > In article <>,
    > G Klinedinst <> wrote:
    > :> # You should avoid the unnecessary concatenations you had in your code.
    >
    > :Why is that? Are the commas implemented faster, or just for
    > :readability?
    >
    > Commas in print's are converted into concatenation internally, so both
    > have the same execution speed.


    Got a question about the paragraph above ...

    [snip]

    Remember reading somewhere that there is a difference between the two, so I
    tried this:

    bash-2.05b$ cat bench && bench
    #!/usr/bin/perl -w
    use strict;
    use Benchmark;

    my $str = 'x' x 100_000;
    my $null = ($^O !~ /win/i) ? '/dev/null' : 'nul';
    open(NULL, ">$null") or die $!;

    timethese(10_000, {
        commas => sub {print NULL $str, $str, $str, $str},
        concat => sub {print NULL $str . $str . $str . $str}
    });

    __END__
    Benchmark: timing 10000 iterations of commas, concat...
    commas:  3 wallclock secs ( 0.67 usr +  1.71 sys =  2.38 CPU)
    @ 4196.72/s (n=10000)

    concat:  6 wallclock secs ( 3.88 usr +  1.70 sys =  5.58 CPU)
    @ 1792.72/s (n=10000)

    Please correct the usage if I made a mistake - rarely use Benchmark, as I
    still have a lot to learn and am trying to concentrate on writing readable
    good code versus writing fast code. But I would like to understand why
    there is a speed difference - is it actually the case that 'Commas in
    print's are converted into concatenation internally'. Is this even
    something to be concerned about?

    thanks in advance - keith
     
    ko, Feb 7, 2004
    #9
  10. In article <c01ncm$rtq$>,
    ko <> wrote:
    :Walter Roberson wrote:
    :> Commas in print's are converted into concatenation internally, so both
    :> have the same execution speed.

    :Got a question about the paragraph above ...

    You think I can find the part of the documentation I was thinking of?
    No.... :(
    --
    Those were borogoves and the momerathsoutgrabe completely mimsy.
     
    Walter Roberson, Feb 7, 2004
    #10
  11. (G Klinedinst) wrote in
    news::

    > Unfortunately the arrays hold an index to another array, which
    > basically tells which input fields were filled out, so some of the
    > arrays are going to be empty(due to the user not entering any data at
    > that position).


    In that case, maybe parallel arrays are not the right data structure for
    the problem. How about using a hash?

    >> # You should avoid the unnecessary concatenations you had in
    >> # your code.
    >>
    >> print "\n\n" ;
    >>
    >> test(\@arr1, \@arr2);
    >>
    >> sub test {
    >> my ($subArr1, $subArr2) = @_;
    >>
    >> print $subArr1->[0], ':', scalar @{$subArr1}, "\n" ;
    >> print $subArr2->[0], ':', scalar @{$subArr2}, "\n" ;
    >> }

    >
    > Why is that? Are the commas implemented faster, or just for
    > readability?


    Well, at least in my mind, the above is an improvement in readability and
    maintainability.

    > Just curious. It's a habit I picked up from Java so now
    > even my Perl code looks like that.


    I know and hate the constant String additions in Java :)

    > I hope things are starting to warm up there in Ithaca for you.


    Just a little.

    Sinan.

    --
    A. Sinan Unur
    (reverse each component for email address)
     
    A. Sinan Unur, Feb 7, 2004
    #11
  12. G Klinedinst

    Ben Morrow Guest

    ko <> wrote:
    > Walter Roberson wrote:
    >
    > > In article <>,
    > > G Klinedinst <> wrote:
    > > :> # You should avoid the unnecessary concatenations you had in your code.
    > >
    > > :Why is that? Are the commas implemented faster, or just for
    > > :readability?
    > >
    > > Commas in print's are converted into concatenation internally, so both
    > > have the same execution speed.

    >
    > Got a question about the paragraph above ...
    >
    > Remember reading somewhere that there is a difference between the two, so I
    > tried this:

    <snip benchmark>

    A tool I like for answering this sort of question is B::Graph, which
    produces a graph of the optree. It seems that

    print "a", "b";

    becomes

    nextstate -> pushmark -> const -> const -> print

    (nextstate starts a new statement. pushmark makes a mark in the Perl
    stack to show where the arguments for the print begin. The consts push
    items onto the stack, the print takes them off down to the mark and
    prints them) whereas

    print "a" . "b";

    becomes

    nextstate -> pushmark -> const -> print

    ie. perl will perform the concatenation at compile time, and thus it
    must be more efficient. However,

    print "a", $x;

    becomes

    nextstate -> pushmark -> const -> padsv -> print

    as before (padsv gets the value of the variable and pushes it onto the
    stack) whereas

    print "a" . $x;

    becomes

    nextstate -> pushmark -> const -> padsv -> concat -> print

    ie. the concatenation is done as a separate step before the print, so
    it may well be slower (this depends on whether printing several items
    as opposed to one is slower or faster than concatenating them).

    Certainly it is not true that they are the same: I suspect Walter was
    thinking of

    print "a$x";

    which *is* converted into

    print "a" . $x;

    internally.

    Ben

    --
    Heracles: Vulture! Here's a titbit for you / A few dried molecules of the gall
    From the liver of a friend of yours. / Excuse the arrow but I have no spoon.
    (Ted Hughes, [ Heracles shoots Vulture with arrow. Vulture bursts into ]
    /Alcestis/) [ flame, and falls out of sight. ]
     
    Ben Morrow, Feb 7, 2004
    #12
  13. G Klinedinst

    ko Guest

    Ben Morrow wrote:

    [snip]

    > A tool I like for answering this sort of question is B::Graph, which
    > produces a graph of the optree. It seems that
    >
    > print "a", "b";
    >
    > becomes
    >
    > nextstate -> pushmark -> const -> const -> print
    >
    > (nextstate starts a new statement. pushmark makes a mark in the Perl
    > stack to show where the arguments for the print begin. The consts push
    > items onto the stack, the print takes them off down to the mark and
    > prints them) whereas
    >
    > print "a" . "b";
    >
    > becomes
    >
    > nextstate -> pushmark -> const -> print
    >
    > ie. perl will perform the concatenation at compile time, and thus it
    > must be more efficient. However,
    >
    > print "a", $x;
    >
    > becomes
    >
    > nextstate -> pushmark -> const -> padsv -> print
    >
    > as before (padsv gets the value of the variable and pushes it onto the
    > stack) whereas
    >
    > print "a" . $x;
    >
    > becomes
    >
    > nextstate -> pushmark -> const -> padsv -> concat -> print
    >
    > ie. the concatenation is done as a separate step before the print, so
    > it may well be slower (this depends on whether printing several items
    > as opposed to one is slower or faster than concatenating them).
    >
    > Certainly it is not true that they are the same


    [snip]

    Perl's internals are over my head, but thank you for providing a simple,
    concise explanation that makes sense. Have never used any of the B
    modules and tried to play around with B::Graph, but couldn't figure out
    how to get output like yours :( . But there's a link at the bottom of
    the documentation, so I'll look at that and at perlguts.

    keith
     
    ko, Feb 8, 2004
    #13
  14. G Klinedinst

    Ben Morrow Guest

    ko <> wrote:
    > Have never used any of the B
    > modules and tried to play around with B::Graph, but couldn't figure out
    > how to get output like yours :( . But there's a link at the bottom of
    > the documentation, so I'll look at that and at perlguts.


    You need dot from http://www.research.att.com/sw/tools/graphviz/; then
    run

    perl -MO=Graph,-dot -e'...program...' | dot -Tps > ops.ps

    .. Then look at ops.ps with a PostScript viewer. If you prefer, you can
    use -Tgif for GIF output.

    I have found that anything more complex than is reasonable on the
    command-line will crash dot :(.

    Ben

    --
    Joy and Woe are woven fine,
    A Clothing for the Soul divine William Blake
    Under every grief and pine 'Auguries of Innocence'
    Runs a joy with silken twine.
     
    Ben Morrow, Feb 8, 2004
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Thomas Christmann

    Problem with passing dynamic arrays by reference

    Thomas Christmann, Aug 31, 2004, in forum: C Programming
    Replies:
    3
    Views:
    413
    Martin Ambuhl
    Aug 31, 2004
  2. Rahul S.
    Replies:
    3
    Views:
    610
    Flash Gordon
    Nov 1, 2004
  3. Philipp
    Replies:
    21
    Views:
    1,156
    Philipp
    Jan 20, 2009
  4. fshort

    Object Reference Error. Pls Help!

    fshort, Feb 26, 2006, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    218
    fshort
    Feb 26, 2006
  5. Jags Rao
    Replies:
    5
    Views:
    134
    Christopher Dicely
    Feb 13, 2009
Loading...

Share This Page