Difficulty with slice of referenced array

Discussion in 'Perl Misc' started by Henry Law, Nov 10, 2004.

  1. Henry Law

    Henry Law Guest

    This doesn't seem to be a FAQ; I tried Googling but couldn't find a
    suitable search string to get a manageable set of results ...

    This is the core of my code:

    #! /usr/bin/perl

    use strict;
    use warnings;

    use Date::Calc qw(
    Date_to_Text
    );

    my @LoL;
    push @LoL, [2001,12,25,"foo"];
    push @LoL, [2004,4,6,"bar"];

    # Gives expected output
    foreach my $lref (@LoL) {
    print Date_to_Text($lref->[0],$lref->[1],$lref->[2]),"\n";
    }

    foreach my $lref (@LoL) {
    # Fails with message "Use of uninitialized value in range (or flip)"
    print Date_to_Text( $lref->[0..2] ), "\n";
    }
    __END__

    I expected $lref->[0..2] to be a slice consisting of the first three
    elements of the array pointed to by $lref, i.e. the same as
    ($lref->[0],$lref->[1],$lref->[2])) but plainly it's not. In order to
    get an array to pass to my subroutine am I condemned to coding the
    elements separately, or is there a correct way of coding the slice?

    Looking up flip-flops I can see that I've got some array-scalar
    problem in the code, but I haven't been able to puzzle out what it is.
    Can someone point me in the right direction?

    Henry Law <>< Manchester, England
     
    Henry Law, Nov 10, 2004
    #1
    1. Advertising

  2. Henry Law

    Anno Siegel Guest

    Henry Law <> wrote in comp.lang.perl.misc:
    > This doesn't seem to be a FAQ; I tried Googling but couldn't find a
    > suitable search string to get a manageable set of results ...
    >
    > This is the core of my code:
    >
    > #! /usr/bin/perl
    >
    > use strict;
    > use warnings;
    >
    > use Date::Calc qw(
    > Date_to_Text
    > );
    >
    > my @LoL;
    > push @LoL, [2001,12,25,"foo"];
    > push @LoL, [2004,4,6,"bar"];
    >
    > # Gives expected output
    > foreach my $lref (@LoL) {
    > print Date_to_Text($lref->[0],$lref->[1],$lref->[2]),"\n";
    > }
    >
    > foreach my $lref (@LoL) {
    > # Fails with message "Use of uninitialized value in range (or flip)"
    > print Date_to_Text( $lref->[0..2] ), "\n";
    > }
    > __END__
    >
    > I expected $lref->[0..2] to be a slice consisting of the first three
    > elements of the array pointed to by $lref, i.e. the same as
    > ($lref->[0],$lref->[1],$lref->[2])) but plainly it's not.


    Indeed it isn't. $lref->[ ...] is always a scalar, In fact it's
    syntactic sugar for ${ $lref}[ ...].

    > In order to
    > get an array to pass to my subroutine am I condemned to coding the
    > elements separately, or is there a correct way of coding the slice?


    There is. What you want is the equivalent of @array[ 0 .. 2],
    but with a ref to @array, not @array itself. The rule is: Replace
    the name ("array") with a reference enclosed in {}. So what you're
    looking for is

    @{ $lref}[ 0 .. 2];

    > Looking up flip-flops I can see that I've got some array-scalar
    > problem in the code, but I haven't been able to puzzle out what it is.
    > Can someone point me in the right direction?


    That error message has come a long way.

    In $lref[ 0 .. 2], what is inside [] is in scalar context (since it
    can't be a slice, there can only ever be one scalar in the []). Now,
    ".." in scalar context has the (somewhat dubious) peculiarity that
    it compares literal operands to $., the variable that holds the line
    number from the last file read. That means, it has assumed you had
    written "$lref[ $. == 0 .. $. == 2]. Now, you're not reading a file,
    so $. is undefined, and that is what it complains about.

    Anno
     
    Anno Siegel, Nov 10, 2004
    #2
    1. Advertising

  3. Henry Law

    Anno Siegel Guest

    Henry Law <> wrote in comp.lang.perl.misc:
    > This doesn't seem to be a FAQ; I tried Googling but couldn't find a
    > suitable search string to get a manageable set of results ...
    >
    > This is the core of my code:
    >
    > #! /usr/bin/perl
    >
    > use strict;
    > use warnings;
    >
    > use Date::Calc qw(
    > Date_to_Text
    > );
    >
    > my @LoL;
    > push @LoL, [2001,12,25,"foo"];
    > push @LoL, [2004,4,6,"bar"];
    >
    > # Gives expected output
    > foreach my $lref (@LoL) {
    > print Date_to_Text($lref->[0],$lref->[1],$lref->[2]),"\n";
    > }
    >
    > foreach my $lref (@LoL) {
    > # Fails with message "Use of uninitialized value in range (or flip)"
    > print Date_to_Text( $lref->[0..2] ), "\n";
    > }
    > __END__
    >
    > I expected $lref->[0..2] to be a slice consisting of the first three
    > elements of the array pointed to by $lref, i.e. the same as
    > ($lref->[0],$lref->[1],$lref->[2])) but plainly it's not.


    Indeed it isn't. $lref->[ ...] is always a scalar, In fact it's
    syntactic sugar for ${ $lref}[ ...].

    > In order to
    > get an array to pass to my subroutine am I condemned to coding the
    > elements separately, or is there a correct way of coding the slice?


    There is. What you want is the equivalent of @array[ 0 .. 2],
    but with a ref to @array, not @array itself. The rule is: Replace
    the name ("array") with a reference enclosed in {}. So what you're
    looking for is

    @{ $lref}[ 0 .. 2];

    > Looking up flip-flops I can see that I've got some array-scalar
    > problem in the code, but I haven't been able to puzzle out what it is.
    > Can someone point me in the right direction?


    That error message has come a long way.

    In $lref->[ 0 .. 2], what is inside [] is in scalar context (since it
    can't be a slice, there can only ever be one scalar in the []). Now,
    ".." in scalar context has the (somewhat dubious) peculiarity that
    it compares literal operands to $., the variable that holds the line
    number from the last file read. That means, it has assumed you had
    written "$lref[ $. == 0 .. $. == 2]. Now, you're not reading a file,
    so $. is undefined, and that is what it complains about.

    Anno
     
    Anno Siegel, Nov 10, 2004
    #3
  4. Henry Law

    Henry Law Guest

    On 10 Nov 2004 12:54:45 GMT, -berlin.de (Anno
    Siegel) wrote:

    >Henry Law <> wrote in comp.lang.perl.misc:


    >> foreach my $lref (@LoL) {
    >> # Fails with message "Use of uninitialized value in range (or flip)"
    >> print Date_to_Text( $lref->[0..2] ), "\n";


    >That error message has come a long way.
    >
    >In $lref[ 0 .. 2], what is inside [] is in scalar context (since it
    >can't be a slice, there can only ever be one scalar in the []). Now,
    >".." in scalar context has the (somewhat dubious) peculiarity that
    >it compares literal operands to $., the variable that holds the line
    >number from the last file read. That means, it has assumed you had
    >written "$lref[ $. == 0 .. $. == 2]. Now, you're not reading a file,
    >so $. is undefined, and that is what it complains about.


    Strewth ... it takes a Perl black belt to work that one out. Thank
    you for this wonderful explanation, and also for guidance on the
    correct way to code a slice of a referenced array. I'm going to
    understand this stuff sooner or later, really I am.

    Henry Law <>< Manchester, England
     
    Henry Law, Nov 10, 2004
    #4
  5. -berlin.de (Anno Siegel) writes:
    > Henry Law <> wrote in comp.lang.perl.misc:
    > > This doesn't seem to be a FAQ; I tried Googling but couldn't find a
    > > suitable search string to get a manageable set of results ...
    > >
    > > This is the core of my code:
    > >
    > > #! /usr/bin/perl
    > >
    > > use strict;
    > > use warnings;
    > >
    > > use Date::Calc qw(
    > > Date_to_Text
    > > );
    > >
    > > my @LoL;
    > > push @LoL, [2001,12,25,"foo"];
    > > push @LoL, [2004,4,6,"bar"];
    > >
    > > # Gives expected output
    > > foreach my $lref (@LoL) {
    > > print Date_to_Text($lref->[0],$lref->[1],$lref->[2]),"\n";
    > > }
    > >
    > > foreach my $lref (@LoL) {
    > > # Fails with message "Use of uninitialized value in range (or flip)"
    > > print Date_to_Text( $lref->[0..2] ), "\n";
    > > }
    > > __END__
    > >
    > > I expected $lref->[0..2] to be a slice consisting of the first three
    > > elements of the array pointed to by $lref, i.e. the same as
    > > ($lref->[0],$lref->[1],$lref->[2])) but plainly it's not.

    >
    > Indeed it isn't. $lref->[ ...] is always a scalar, In fact it's
    > syntactic sugar for ${ $lref}[ ...].
    >
    > > In order to
    > > get an array to pass to my subroutine am I condemned to coding the
    > > elements separately, or is there a correct way of coding the slice?

    >
    > There is. What you want is the equivalent of @array[ 0 .. 2],
    > but with a ref to @array, not @array itself. The rule is: Replace
    > the name ("array") with a reference enclosed in {}. So what you're
    > looking for is
    >
    > @{ $lref}[ 0 .. 2];
    >
    > > Looking up flip-flops I can see that I've got some array-scalar
    > > problem in the code, but I haven't been able to puzzle out what it is.
    > > Can someone point me in the right direction?

    >
    > That error message has come a long way.
    >
    > In $lref[ 0 .. 2], what is inside [] is in scalar context (since it
    > can't be a slice, there can only ever be one scalar in the []). Now,
    > ".." in scalar context has the (somewhat dubious) peculiarity that
    > it compares literal operands to $., the variable that holds the line
    > number from the last file read. That means, it has assumed you had
    > written "$lref[ $. == 0 .. $. == 2]. Now, you're not reading a file,
    > so $. is undefined, and that is what it complains about.


    I condensed the program to this while trying to understand what
    happens. (The $i stuff was in order to have a loop without using any
    ... construct which might influence flip-flops.) I don't understand
    what happens when I have "use diagnostics" on:

    #! /usr/bin/perl -w

    use strict;
    #use diagnostics;

    my $lref = [1,2,3,4,5,6,7,8];

    for (my $i = 0; $i < 6; $i++) {
    my $l2 = $lref->[0 .. 2];

    print "l2 = $l2\n";
    }

    This prints

    Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    l2 = 1
    Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    l2 = 1
    Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    l2 = 1
    Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    l2 = 1
    Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    l2 = 1
    Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    l2 = 1

    as more or less expected from your explanation. But when I remove the
    comment marker from the "use diagnostics" line, I get:

    l2 = 2
    l2 = 3
    l2 = 4
    l2 = 5
    l2 = 6
    l2 = 7

    and no warnings. This I don't understand at all. (I'm on Perl 5.005,
    in case it matters.)


    Two minor questions, also:

    1) Would it be bad style to write @$lref[0..2] rather than
    @{$lref}[0..2]?

    2) To help the original poster, would it be correct to say that
    something beginning with '$' produces a scalar, and something
    beginning with '@' produces a list or array? This principle would show
    that $lref->[0..2] can't be an array slice. (But it wouldn't help
    explain why @lref->[0..2] isn't the solution, of course...)
     
    Arndt Jonasson, Nov 10, 2004
    #5
  6. Arndt Jonasson <> wrote in
    news::

    > I condensed the program to this while trying to understand what
    > happens. (The $i stuff was in order to have a loop without using any
    > .. construct which might influence flip-flops.) I don't understand
    > what happens when I have "use diagnostics" on:


    That I don't understand either.

    However ...

    > #! /usr/bin/perl -w
    >
    > use strict;
    > #use diagnostics;
    >
    > my $lref = [1,2,3,4,5,6,7,8];


    $lref is not a reference to a list. It is a reference to an anonymous
    array. Hence, the first letter is a little misleading, esp in light of
    your later comment.

    > Two minor questions, also:
    >
    > 1) Would it be bad style to write @$lref[0..2] rather than
    > @{$lref}[0..2]?


    Depends on context.

    > 2) To help the original poster, would it be correct to say that
    > something beginning with '$' produces a scalar, and something
    > beginning with '@' produces a list or array?


    perldoc -q list

    Sinan.
     
    A. Sinan Unur, Nov 10, 2004
    #6
  7. Henry Law

    Anno Siegel Guest

    Arndt Jonasson <> wrote in comp.lang.perl.misc:

    > I condensed the program to this while trying to understand what
    > happens. (The $i stuff was in order to have a loop without using any
    > .. construct which might influence flip-flops.) I don't understand
    > what happens when I have "use diagnostics" on:
    >
    > #! /usr/bin/perl -w
    >
    > use strict;
    > #use diagnostics;
    >
    > my $lref = [1,2,3,4,5,6,7,8];
    >
    > for (my $i = 0; $i < 6; $i++) {
    > my $l2 = $lref->[0 .. 2];
    >
    > print "l2 = $l2\n";
    > }
    >
    > This prints
    >
    > Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    > l2 = 1
    > Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    > l2 = 1
    > Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    > l2 = 1
    > Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    > l2 = 1
    > Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    > l2 = 1
    > Argument "" isn't numeric in aelem at ./bar2.pl line 10.
    > l2 = 1
    >
    > as more or less expected from your explanation. But when I remove the
    > comment marker from the "use diagnostics" line, I get:
    >
    > l2 = 2
    > l2 = 3
    > l2 = 4
    > l2 = 5
    > l2 = 6
    > l2 = 7
    >
    > and no warnings. This I don't understand at all. (I'm on Perl 5.005,
    > in case it matters.)


    diagnostics.pm reads a file during its initialization. As a side
    effect, after "use diagnostics", $. has a defined value (of 0) instead
    of undef without it. That allows "0 .. 2" to start off its sequence
    (1, 2, 3...) of true values (read about it in perlop) which never
    ends because the right operand "$. == 2" never becomes true. That
    gives you the values $lref->[ 1], $lref->[ 2], ... you're seeing.

    > Two minor questions, also:
    >
    > 1) Would it be bad style to write @$lref[0..2] rather than
    > @{$lref}[0..2]?


    It's possible, but the precedence rules that allow you to leave
    out the {} are pretty obscure. Except for the most simple cases
    I would recommend to leave them in.

    > 2) To help the original poster, would it be correct to say that
    > something beginning with '$' produces a scalar, and something
    > beginning with '@' produces a list or array? This principle would show
    > that $lref->[0..2] can't be an array slice. (But it wouldn't help
    > explain why @lref->[0..2] isn't the solution, of course...)


    ....nor is the rule "if it begins with $, it's a scalar" without
    exceptions. Think of "$x = sub { 1, 2, 3 }; @y = $x->();". So
    I prefer not to quote that rule, it only leads to more discussion... :)

    Anno
     
    Anno Siegel, Nov 10, 2004
    #7
  8. "A. Sinan Unur" <> writes:
    > Arndt Jonasson <> wrote in
    > news::
    > > my $lref = [1,2,3,4,5,6,7,8];

    >
    > $lref is not a reference to a list. It is a reference to an anonymous
    > array. Hence, the first letter is a little misleading, esp in light of
    > your later comment.


    Sorry about that, but I kept the name "lref" from the original question.
     
    Arndt Jonasson, Nov 10, 2004
    #8
  9. Henry Law <> wrote in
    news::

    > This doesn't seem to be a FAQ; I tried Googling but couldn't find a
    > suitable search string to get a manageable set of results ...

    [...]
    > I expected $lref->[0..2] to be a slice consisting of the first three
    > elements of the array pointed to by $lref, i.e. the same as
    > ($lref->[0],$lref->[1],$lref->[2])) but plainly it's not. In order to
    > get an array to pass to my subroutine am I condemned to coding the
    > elements separately, or is there a correct way of coding the slice?


    Anno Siegel has already given you a fine answer, but I would like to
    amend it. He gave you

    @{$lref}[0..2]

    which is fine and all, but I greatly prefer the simpler

    @$lref[0..2]

    You know that the leading character (the 'sigil') must be $ if what you
    will end up with is a scalar, and @ if what you'll end up with is an
    array (er, list. You know). So, for a scalar dereference of an
    arrayref, use

    $foo->[$index]

    and for an array slice dereference of an arrayref, use

    @$foo[$index, $index, ...]

    You don't need the -> (and in fact, it'd be an error to use it), because
    $foo doesn't need to be further dereferenced after the @.

    Bonus: For an array slice of a hash reference, use

    @$foo{$key, $key, $key}

    Once you grok all of the above notations, you will be well on your way to
    Perl reference mastery, my son.

    --
    Eric
    `$=`;$_=\%!;($_)=/(.)/;$==++$|;($.,$/,$,,$\,$",$;,$^,$#,$~,$*,$:,@%)=(
    $!=~/(.)(.).(.)(.)(.)(.)..(.)(.)(.)..(.)......(.)/,$"),$=++;$.++;$.++;
    $_++;$_++;($_,$\,$,)=($~.$"."$;$/$%[$?]$_$\$,$:$%[$?]",$"&$~,$#,);$,++
    ;$,++;$^|=$";`$_$\$,$/$:$;$~$*$%[$?]$.$~$*${#}$%[$?]$;$\$"$^$~$*.>&$=`
     
    Eric J. Roode, Nov 14, 2004
    #9
    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. Robert TV

    Difficulty removing element from array

    Robert TV, Sep 21, 2003, in forum: Perl Misc
    Replies:
    3
    Views:
    109
    Eric J. Roode
    Sep 21, 2003
  2. .rhavin
    Replies:
    7
    Views:
    122
    Heinrich Mislik
    Oct 8, 2004
  3. Replies:
    9
    Views:
    269
    David Squire
    May 22, 2006
  4. Replies:
    3
    Views:
    103
    Tad J McClellan
    Nov 11, 2008
  5. feltra
    Replies:
    2
    Views:
    118
    J├╝rgen Exner
    Sep 25, 2010
Loading...

Share This Page