How can this be?

M

Mr P

How could this error ever occur?

Type of arg 1 to shift must be array (not split)

split() creates an array, shift expects an array. shift() sees a scalar
returned? You'd think in this context split() would produce an array?

Why can't they all just get along!?

:)
 
P

Paul Lalli

Mr said:
How could this error ever occur?

Type of arg 1 to shift must be array (not split)

split() creates an array
False.

shift expects an array.
True.

shift() sees a scalar returned?

No idea what that means.
You'd think in this context split() would produce an array?

split never produces an array.
Why can't they all just get along!?

You need to learn the difference between a list and an array:
perldoc -q "list and an array"

Paul Lalli
 
T

Tad McClellan

Mr P said:
split() creates an array,


What made you think that?

The first sentence of the docs for split

Splits a string into a list of strings and returns that list.

says rather clearly that split() returns a *list*.

You'd think in this context split() would produce an array?


Functions in Perl *never* return (not "produce") arrays, only lists.
 
A

A. Sinan Unur

How could this error ever occur?

Type of arg 1 to shift must be array (not split)

split() creates an array, shift expects an array. shift() sees a scalar
returned? You'd think in this context split() would produce an array?

If all you want is the first element of the list created by split, you
could do

my $v = (split)[0];

Sinan
 
T

Tad McClellan

A. Sinan Unur said:
How could this error ever occur?

Type of arg 1 to shift must be array (not split)

split() creates an array, shift expects an array. shift() sees a scalar
returned? You'd think in this context split() would produce an array?

If all you want is the first element of the list created by split, you
could do

my $v = (split)[0];


or even

my($v) = split;
 
M

Mr P

Thank-You. Please elaborate...

If THIS works:

my @a = split /regex/, @a2;

which is essentially, if I understand you, saying:

my array = a list

so why can't I do:

my array = shift (a list)

In other words, its OK to ASSIGN a list to an array (which would have
to be interpreted or coerced into an array) , but I can't use the shift
operator on a list. Using this same rule, why can't the list be coerced
intro an array for the purpose of shifting it?

Its pretty obvioius what the code is TRYING to do - and knowing Larry
as well as I do, he usually tries to make things work as you'd expect
them to. Except in some cases like this.

Weird. These restrictions make pipelined operations very awkward in
Perl... It would be clean syntax to use:

my @a = grep ... shift ... split, $scalar;
 
J

Josef Moellers

Mr said:
Thank-You. Please elaborate...

If THIS works:

my @a = split /regex/, @a2;

No it won't: split requires a string as the second argument, not an array.
which is essentially, if I understand you, saying:

my array = a list

so why can't I do:

my array = shift (a list)

Quite simple, for the same reason why you can't do
$x = 5++; # Set $x to 6
or
$y = int(5.3)--; # Set $y to int(5.3)-1

A list is a constant item and shift requires an lvalue, i.e. an item it
can modify as a side effect.
As you are interested in the first value (you cannot perform the side
effect), you can do

my $value = (split /regex/, @a2)[0];

Josef
 
P

Paul Lalli

Mr said:
Thank-You. Please elaborate...

If THIS works:

my @a = split /regex/, @a2;

Not entirely sure what you think that's doing. It's trying to split
the string representing the *size* of @a2 by /regexp/. I'm guessing
you meant something more like:
my @a = split /regex/, $string;
which is essentially, if I understand you, saying:

my array = a list

Putting this into proper Perl code:
my @array = (1, 2, 3, 4, 5);

This is assigning an array variable to have the value of the list
containing 1, 2, 3, 4, and 5.
so why can't I do:

my array = shift (a list)

For the same reason that you can't do:

23 = "hello world";

A list is a *value*. Another name for a list is a "list literal". It
is not a variable that can be modified. The shift() function returns
*and removes* the first element of its array. That is, it directly
modifies its argument. A list is not something modifiable.

Consider this: the substr() function can produce an lvalue, if its
argument is itself an lvalue:
my $string = "Hello World";
substr($string, 1, 3) = "FOOBAR";
# $string now ==> "HFOOBARo World"

That works because $string can be assigned to, so therefore parts of
$string can be assigned to, changed, modified, deleted, etc. However,
if you were to pass substr a value that cannot be modified:
substr ("Hello World", 1, 3) = "FOOBAR";
You would get the error: Can't modify constant item in scalar
assignment

In this second example, the string "Hello World" is a literal, a
constant. It cannot be altered. The same applies to a list. An array
is a variable that can be assigned to, changed, modified, etc. A list
is a constant sequence of scalar values.

Have you read
perldoc -q "list and an array"
yet?
In other words, its OK to ASSIGN a list to an array (which would have
to be interpreted or coerced into an array), but I can't use the shift
operator on a list. Using this same rule, why can't the list be coerced
intro an array for the purpose of shifting it?

I don't understand what you mean by "coerced". An array is a Perl
variable that holds a given value at any given time. A list is a
sequence of values.

my @array = (1..5);
assigns a value to @array the same way
my $string = "Hello World";
assigns a value to $string
Its pretty obvioius what the code is TRYING to do

No, it's not obvious to me at all. What effect are you going for when
you try to shift a constant list? shift() returns *and removes* the
first element of an array. What would be the effect of removing an
element from a constant list?

If you're going for the first part of my description - the *returning*
of the first element, just do it directly:

my $first = (split /regexp/, $string)[0];
- and knowing Larry
as well as I do, he usually tries to make things work as you'd expect
them to. Except in some cases like this.

I think you're the only one expecting this to work any differently than
it does, unfortunately.
Weird. These restrictions make pipelined operations very awkward in
Perl...

No, it doesn't. You're just using the wrong function/operator for your
goal.
It would be clean syntax to use:
my @a = grep ... shift ... split, $scalar;

Hrm. I *think* what you're going for here is to have the grep operate
on everything *except* the first element of the list returned by split.
Is that correct?

Unfortunately, I can't think of any particular way to do this. But I
consider that a failure of list slices, not of the shift() function.

(Any one else able to come up with a way of doing this "in-line",
without assigning to a temp variable, or knowing in advance how many
fields are contained in $scalar?)

Paul Lalli
 
P

Paul Lalli

Paul said:
Hrm. I *think* what you're going for here is to have the grep operate
on everything *except* the first element of the list returned by split.
Is that correct?

Unfortunately, I can't think of any particular way to do this. But I
consider that a failure of list slices, not of the shift() function.

(Any one else able to come up with a way of doing this "in-line",
without assigning to a temp variable, or knowing in advance how many
fields are contained in $scalar?)

Well, actually I can think of a couple ways to do this. One is
massively ugly an inefficient:
my @a = grep {$_ > 2} (split /re/,
$scalar)[1..scalar(()=$scalar=~m/re/g)];
That determines how many times regex is contained in $scalar, using
m//g in list context and *that* in scalar context, and then using the
result as the upper bound to the range operator in the list slice.
Like I said, ugly.

The other, more obvious way would be to just define a subroutine that
returns all-but-the-first argument passed in:

sub remainder {
@_[1..$#_];
}
my @a = grep {$_ > 2} remainder split /re/, $scalar;

(Of course, this does violate my original request for not using a
temporary array, as we're implicitly using the @_ array)

Paul Lalli
 
A

A. Sinan Unur

Thank-You. Please elaborate...

Please quote an appropriate amount of context.
If THIS works:

my @a = split /regex/, @a2;

Others have managed to read your mind.
which is essentially, if I understand you, saying:

my array = a list

so why can't I do:

my array = shift (a list)

Others have explained why this is non-sensical.

However, you can always create an anonymous array using the list value
returned by shift:

#!/usr/bin/perl

use strict;
use warnings;

my $s = 'a,b,c,d,e,f';

my $x = shift @{ [ split /,/, $s ]};
print "$x\n";

There is, however, not too many good reasons to do that.

my ($y) = split /,/, $s;
print "$y\n";
In other words, its OK to ASSIGN a list to an array (which would have
to be interpreted or coerced into an array),

I don't see the great scandal here.

You can do

my $x = 5;

but you cannot do

my 5 = $x;
but I can't use the shift operator on a list.

That would be essentially the same thing as the second example.
Using this same rule, why can't the list be coerced
intro an array for the purpose of shifting it?

If you did want to "coerce", as shown in the sample above, you could
coerce the returned list into an anonymous array, and shift that.
Its pretty obvioius what the code is TRYING to do - and knowing Larry
as well as I do,

Well, maybe you can take it up with him then.
Weird. These restrictions make pipelined operations very awkward in
Perl... It would be clean syntax to use:

my @a = grep ... shift ... split, $scalar;

That looks more than a little silly to me: Why would you grep with a
scalar? Why do you think assigning the result of whatever you intend to
do above (and it is not really obvious) to an array makes sense?

Sinan
 
A

Anno Siegel

Paul Lalli said:
Paul said:
Hrm. I *think* what you're going for here is to have the grep operate
on everything *except* the first element of the list returned by split.
Is that correct?

Unfortunately, I can't think of any particular way to do this. But I
consider that a failure of list slices, not of the shift() function.

(Any one else able to come up with a way of doing this "in-line",
without assigning to a temp variable, or knowing in advance how many
fields are contained in $scalar?)

Well, actually I can think of a couple ways to do this. One is
massively ugly an inefficient:
my @a = grep {$_ > 2} (split /re/,
$scalar)[1..scalar(()=$scalar=~m/re/g)];
That determines how many times regex is contained in $scalar, using

....violating the condition "(not) knowing in advance how many fields are
contained in $scalar".
m//g in list context and *that* in scalar context, and then using the
result as the upper bound to the range operator in the list slice.
Like I said, ugly.

The other, more obvious way would be to just define a subroutine that
returns all-but-the-first argument passed in:

sub remainder {
@_[1..$#_];
}
my @a = grep {$_ > 2} remainder split /re/, $scalar;

(Of course, this does violate my original request for not using a
temporary array, as we're implicitly using the @_ array)

Right. It can't be done.

Anno
 

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,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top