jynx has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monks,

Recently there was a post on array refs that had a follow-up stating you could force a list into array context using @{[ &make_list_here ]}. This isn't what i'm doing. But it relates...

A general warning, yes, i could use Parse::RecDescent, but i'm still trying to do some things the hard way to learn why other things work the way they do.

So i'm parsing a file and most of the data is flat, but there are sometimes when i want to get a hash out of the data. So the code i use is:

# this is in a loop that iterates through the file # and at some point it runs across: /(\S+)\s?=?\s?\[(.+)\]$/ && do { $hash{$1} = split /,/, $2; next; };

This works, but with warnings i got the message:
Use of implicit split to @_ is deprecated
Looking this up it says i was assigning to @_, but it doesn't look like that at all to me. That looks like assingment to a hash entry as an anonymous list. When i apply the context generating code above like so:
/(\S+)\s?=?\s?\[(.+)\]$/ && do { $hash{$1} = @{[ split /,/, $2 ]}; next; };
the error message goes away. i'm glad the message is gone, but i'm wondering why it gave that error message (which seems inappropriate) and why this fixed it.

please enlighten this quandering quaffer of quintessential qualms (or not ; )

jynx

Replies are listed 'Best First'.
Re: list vs array context: odd error message...
by swiftone (Curate) on Dec 16, 2000 at 04:27 UTC
     $hash{$1} = split /,/, $2;
    Looking this up it says i was assigning to @_, but it doesn't look like that at all to me. That looks like assingment to a hash entry as an anonymous list.

    Close, but no cigar. You were assigning an array (the @_) to a scalar, which translates to the number of elements in the array.

    You want:
    $hash{$1} = [split /,/, $2];

    Which creates the anonymous arrayref you were mentioning, which lives quite happily as a scalar

      So does my inital reponse not accomplish the same thing in another way? I didn't test it, but if memory serves, its effect is identical.

      Hot Pastrami
        It's not identical if there's already something in the hash element. It reuses any existing hashref pointer, and may even fail if there's an arrayref or something else there instead.

        That's why I prefer avoiding the @{$foo[bar]} = ... forms, opting instead for the $foo[bar] = [...] forms as being much safer.

        -- Randal L. Schwartz, Perl hacker

        It does indeed accomplish the same thing, but it obfuscates what you're doing. (You dereference your lvalue, while I make a references of the rvalue). As proof, I wasn't sure your way worked until I tested it. :)

        To each his own.

Re: list vs array context: odd error message...
by chromatic (Archbishop) on Dec 16, 2000 at 04:36 UTC
    To expand a bit on swiftone's point, the construct you have in the first section asks for and receives a side-effect of the split. split always returns a list (a list of one element is still a list). However, your first construct uses split in scalar context. (I presume internally, split doesn't use any sort of wantarray checking.)

    To do what split wants and to do what you want, perl has to assign the list results of the split operation to @_, then evaluate @_ in scalar context, giving you the number of elements. You might as well just use m// with your pattern in scalar context.

    Your second one works because you do as swiftone recommends, creating an anonymous array out of the split results. That puts split in list context. Next, you dereference the anonymous array, and evaluate that in scalar context. Same results, except that wrapping the split in the reference/dereference stuff fools perl just enough that it doesn't give you the error message.

    As for the error message, it means "Try not to do a potentially expensive operation if you're just going to throw away the results."

      thank you much,

      As a question though, would there be a time when it would make sense to use split in scalar context (and thus avoid the @_?). Not as if i'm qualified to ask question's on perl's behavior, but if this is deprecated (as diagnostics says) is it going to be replaced by some other behavior?

      jynx

      UPDATE: please disregard this, i apparently wasn't fully reading the above post (but thanx again swiftone for pointing that out)

        1) I can't think of a time you'd use split in a scalar context. See chromatic's post about m//;

        2) The features of splitting to @_ was there to reduce temporary variables. It's deprecated because it encourages trampling on subroutine arguments.

Re: list vs array context: odd error message...
by chipmunk (Parson) on Dec 16, 2000 at 21:58 UTC
    It seems to me that no one has quite described the behavior of split in scalar context accurately yet.

    First, it should be noted that there is no such thing as array context in Perl. The only contexts are scalar, list, and void (which is a special kind of scalar context). Scalar has several subcontexts, including string, numeric, and boolean. (It's generally accepted that wantarray was misnamed, and should have been wantlist instead.)

    split is almost always used in a list context, where it returns a list of substrings split out from the target string. However, when split is used in a scalar context, as in   $count = split ' ', $string split instead returns the size of the list of substrings. At the same time, the list of substrings is placed in the array @_. In other words, the behavior is effectively   @_ = split ' ', $string; $count = @_;

    This implicit assignment to @_ by split in scalar context is deprecated, which is why you receive a warning. You can avoid the warning by using a temporary array.   $count = @tmp = split ' ', $string

    However, you don't want the count of elements; you want a reference to an array, which you must ask for explicitly.   $ref = [ split ' ', $string ] The anonymous array constructor puts split in list context (remember, there is no such thing as array context) and returns a reference to an array of substrings.

Re: list vs array context: odd error message...
by Hot Pastrami (Monk) on Dec 16, 2000 at 04:23 UTC
    Somebody smarter than me will answer in a moment (or has answered while I typed this), but I believe your problem is because the split is assigning to an array ref rather than a real array. More correct (but probably not MOST correct) would be:
    /(\S+)\s?=?\s?\[(.+)\]$/ && do { @{$hash{$1}} = split /,/, $2; next; };
    (Untested!)

    Hot Pastrami
Re: list vs array context: odd error message...
by Hot Pastrami (Monk) on Dec 16, 2000 at 04:50 UTC
    By the way, the syntax you described, @{[ &make_list_here ]}, is usually for the purposes of having a function interpolated in a string:
    my $string = "This is a @{[ &test() ]}";

    Hot Pastrami