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

Hello monks,

I'm looking for some conceptual explanation of why a few things don't work. The code I have is:

my $line1 = <IN>; chomp($line1); my @row = split("\t", $line1);

I naively thought I could make that a little easier to read by doing:

my @row = split("\t", chomp(<IN>));

Instead I get error messages. The attempt to chomp the file-handle gives this:

Can't modify <HANDLE> in chomp

So after I accepted that and tried just to do:

my $line = <IN>; my @row = split("\t", chomp($line)); print $row[0];

I was surprised to still get an error:

Use of uninitialized value in print


Can anyone shed some light on either of those issues: 1) why one can't chomp() a handle, and 2) why I can't use chomp to return an lvalue?

Replies are listed 'Best First'.
Re: Chomp(<handle>)
by dws (Chancellor) on Jul 14, 2003 at 17:54 UTC
    my @row = split("\t", chomp(<IN>));

    chomp() returns the number of characters removed, not the chomped values. So even if you were to sidestep your immediate problem by doing

    my @row = split("\t", chomp(my $line = <IN>));
    You still wouldn't get what you're expecting.

    chomp() is a special beast. It modifies its arguments. You can't modify a file handle in the same way.

Re: Chomp(<handle>)
by Zaxo (Archbishop) on Jul 14, 2003 at 17:57 UTC

    What you're after is something like,

    chomp(my $line = <IN>); my @row = split /\t/, $line; print $row[0];
    I don't see how you're getting that error in the third example unless $line is coming back as undef. -- Oh, perhaps the first character in $line is a tab!

    After Compline,
    Zaxo

Re: Chomp(<handle>)
by artist (Parson) on Jul 14, 2003 at 18:03 UTC
    Correct answer:

    chomp($line1=<DATA>); my @row = split("\t",$line1) ; print $row[0]; __DATA__ hello world
    Explaination:

    1), From perldoc: You can actually chomp anything that can be an lvalue. FileHandle cannot be an lvalue.
    2), chomp returns the number of characters removed. For the other part, use substr($string,0,-1) type variation.

    artist

Re: Chomp(<handle>) (sub)
by tye (Sage) on Jul 14, 2003 at 19:41 UTC
    sub Chomped($) { my( $line )= @_; chomp( $line ); return $line; } my @row= split /\t/, Chomped(<IN>);
                    - tye
Re: Chomp(<handle>)
by Anonymous Monk on Jul 14, 2003 at 18:14 UTC
    Thanks monks, I think I understand the complexities here a bit more. I have to say, intuitively I had expected chomp to return the modified string, not the number of characters removed. I suppose this indicates my intuition is, err, faulty. :)
Re: Chomp(<handle>)
by BrowserUk (Patriarch) on Jul 14, 2003 at 18:02 UTC

    My best guess as to the reasoning is that chomp was designed to also work as chomp( @array ); and it was more efficient to do this 'in-place', rather than returning the list which would have required copying the whole array.

    I'm not adverse to efficient constructs, but given that in almost every scenario that I can think of, whenever I chomp a scalar, I then need to pass that scalar onto something else, I wish that when chomp was called with a single scalar argument in a scalar context, it would edit the argument in-place and then return an alias to the argument that could be used as an rvalue.

    Its probably too late to change it as I'm sure that there are some circumstances in which this would break existing code. Though, off the top of my head, I can't think of any, but someone will show me the shallowness of my thoughts:)


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


Re: Chomp(<handle>)
by halley (Prior) on Jul 14, 2003 at 18:00 UTC
    The first error is because it can't choose between chomp SCALAR or chomp ARRAY usage. Should it slurp the whole file into an array and chomp that? Or should it slurp one line and chomp that? Using a named intermediary lvalue gives it the proper context to make such choices.

    The second error is what you expected it to return. From (perldoc -f chomp), "It returns the total number of characters removed from all its arguments." So @row gets one element, which is '1'.

    --
    [ e d @ h a l l e y . c c ]

      The first error is because it can't choose between chomp SCALAR or chomp ARRAY usage.

      No, the first error is because he's "passing" something to chomp() that can't be modified in place.

      Try

      chomp(" foo ");
      It's clearly a SCALAR, yet it won't work.

        $ perl -e 'chomp(" foo ");' Can't modify constant item in chomp at - line 1, near "" foo ")"
        $ perl -e 'chomp(<STDIN>);' Can't modify <HANDLE> in chomp at - line 1, near "<STDIN>)"
        Different error messages. In the first case, it complains about modifying a non-lvalue (a constant item). In the second case, it complains about modifying the results of reading from a file handle.

        I'll grant you that chomp SCALAR can't chomp a non-lvalue, if you'll grant that the ambiguous context of the syntax chomp <FOO> is another valid reason that the compiler gives a separate distinct message.

        --
        [ e d @ h a l l e y . c c ]

Re: Chomp(<handle>)
by Mago (Parson) on Jul 14, 2003 at 20:56 UTC
    #!/usr/bin/perl use strict; use warnings; printf("\n >> START PROCESS ...\n"); open (ARQ, "< ./arq.txt"); while ($line = <ARQ>) { chomp($line); printf("[$line]\n"); } printf("\n ... END PROCESS <<\n");
    -------------------------------------------------------

    CHOMP

    chomp VARIABLE
    chomp( LIST )
    chomp

    This safer version of /chop removes any trailing string that corresponds to the current value of $/ (also known as $INPUT_RECORD_SEPARATOR in the English module). It returns the total number of characters removed from all its arguments. It's often used to remove the newline from the end of an input record when you're worried that the final record may be missing its newline. When in paragraph mode ($/ = ""), it removes all trailing newlines from the string. When in slurp mode ($/ = undef) or fixed-length record mode ($/ is a reference to an integer or the like, see perlvar) chomp() won't remove anything. If VARIABLE is omitted, it chomps $_. Example:

    while (<>) { chomp; # avoid \n on last field @array = split(/:/); # ... }
    If VARIABLE is a hash, it chomps the hash's values, but not its keys.

    You can actually chomp anything that's an lvalue, including an assignment:

    chomp($cwd = `pwd`); chomp($answer = <STDIN>);
    If you chomp a list, each element is chomped, and the total number of characters removed is returned.

    Note that parentheses are necessary when you're chomping anything that is not a simple variable. This is because chomp $cwd = `pwd`; is interpreted as (chomp $cwd) = `pwd`;, rather than as chomp( $cwd = `pwd` ) which you might expect. Similarly, chomp $a, $b is interpreted as chomp($a), $b rather than as chomp($a, $b).