How can this be?

Discussion in 'Perl Misc' started by Mr P, Oct 4, 2005.

  1. Mr P

    Mr P Guest

    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!?

    :)
     
    Mr P, Oct 4, 2005
    #1
    1. Advertising

  2. Mr P

    Paul Lalli Guest

    Mr P wrote:
    > 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
     
    Paul Lalli, Oct 4, 2005
    #2
    1. Advertising

  3. Mr P <> wrote:

    > 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.


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Oct 4, 2005
    #3
  4. "Mr P" <> wrote in news:1128446765.998511.294640
    @o13g2000cwo.googlegroups.com:

    > 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


    --
    A. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
     
    A. Sinan Unur, Oct 5, 2005
    #4
  5. A. Sinan Unur <> wrote:
    > "Mr P" <> wrote in news:1128446765.998511.294640
    > @o13g2000cwo.googlegroups.com:
    >
    >> 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;


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Oct 5, 2005
    #5
  6. Mr P

    Mr P Guest

    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;
     
    Mr P, Oct 5, 2005
    #6
  7. Mr P wrote:
    > 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
    --
    Josef Möllers (Pinguinpfleger bei FSC)
    If failure had no penalty success would not be a prize
    -- T. Pratchett
     
    Josef Moellers, Oct 5, 2005
    #7
  8. Mr P

    Paul Lalli Guest

    Mr P wrote:
    > 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
     
    Paul Lalli, Oct 5, 2005
    #8
  9. Mr P

    Paul Lalli Guest

    Paul Lalli wrote:
    > Mr P wrote:
    > > 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?)


    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
     
    Paul Lalli, Oct 5, 2005
    #9
  10. "Mr P" <> wrote in news:1128519319.410668.286630
    @g44g2000cwa.googlegroups.com:

    > 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. Sinan Unur <>
    (reverse each component and remove .invalid for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
     
    A. Sinan Unur, Oct 5, 2005
    #10
  11. Mr P

    Anno Siegel Guest

    Paul Lalli <> wrote in comp.lang.perl.misc:
    > Paul Lalli wrote:
    > > Mr P wrote:
    > > > 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?)

    >
    > 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
    --
    If you want to post a followup via groups.google.com, don't use
    the broken "Reply" link at the bottom of the article. Click on
    "show options" at the top of the article, then click on the
    "Reply" at the bottom of the article headers.
     
    Anno Siegel, Oct 6, 2005
    #11
    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. Bob
    Replies:
    1
    Views:
    396
    Shawn B.
    Jan 12, 2004
  2. Richard Dixson
    Replies:
    1
    Views:
    546
    Joe Fallon
    May 18, 2004
  3. Rutger Smit
    Replies:
    1
    Views:
    553
    =?Utf-8?B?THVrZWI=?=
    Sep 6, 2004
  4. duncan
    Replies:
    2
    Views:
    6,150
  5. Casey Hawthorne
    Replies:
    1
    Views:
    757
    Arne Vajhøj
    Mar 18, 2009
Loading...

Share This Page