Difficulty with slice of referenced array

H

Henry Law

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
 
A

Anno Siegel

Henry Law said:
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
 
A

Anno Siegel

Henry Law said:
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
 
H

Henry Law

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
 
A

Arndt Jonasson

Henry Law said:
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...)
 
A

A. Sinan Unur

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

Anno Siegel

Arndt Jonasson said:
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
 
A

Arndt Jonasson

A. Sinan Unur said:
Arndt Jonasson said:
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.
 
E

Eric J. Roode

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
`$=`;$_=\%!;($_)=/(.)/;$==++$|;($.,$/,$,,$\,$",$;,$^,$#,$~,$*,$:,@%)=(
$!=~/(.)(.).(.)(.)(.)(.)..(.)(.)(.)..(.)......(.)/,$"),$=++;$.++;$.++;
$_++;$_++;($_,$\,$,)=($~.$"."$;$/$%[$?]$_$\$,$:$%[$?]",$"&$~,$#,);$,++
;$,++;$^|=$";`$_$\$,$/$:$;$~$*$%[$?]$.$~$*${#}$%[$?]$;$\$"$^$~$*.>&$=`
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,822
Latest member
israfaceZa

Latest Threads

Top