Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Can a defined value be of zero length?

by reisinge (Hermit)
on Apr 19, 2014 at 09:06 UTC ( [id://1082874]=perlquestion: print w/replies, xml ) Need Help??

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

Dear Monks, why would I need to check for the length of the string? Is it not enough to check for the "definedness"?

use strict; use warnings; my $dir = '/etc'; while (1) { print "Enter pattern> "; chomp( my $pattern = <STDIN> ); ## I'm talking about this line last unless defined $pattern and length $pattern; my @matched = eval { grep { /$pattern/ } glob "$dir/*"; }; print "Error: $@" if $@; print map { "$_\n" } @matched; }

And like that ... he's gone. -- Verbal

Replies are listed 'Best First'.
Re: Can a defined value be of zero length?
by tobyink (Canon) on Apr 19, 2014 at 09:21 UTC
    use strict; use warnings; my $value = q(); printf("Here is a string: \"%s\"\n", quotemeta($value)); printf("Is it defined? %s\n", defined($value) ? "Yes" : "No"); printf("What is its length? %d\n", length($value));
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re: Can a defined value be of zero length?
by LanX (Saint) on Apr 19, 2014 at 09:20 UTC
    What happend when you tried the empty string "" as a value ?

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Can a defined value be of zero length?
by graff (Chancellor) on Apr 19, 2014 at 15:27 UTC
    In the OP script, the defined $pattern condition is entirely unnecessary; the length $pattern condition is sufficient because $pattern will be used as a string, so all that matters is that the string not be empty (and "undef" variables are equivalent to empty strings when passed to length()).

    If you pipe data to the script (e.g. echo fs | your_script), you'll get the prompt string, followed by the expected output, followed by a warning (Use of unitialized value $pattern in chomp…). You also get that warning if you run it "normally" (not piping to its STDIN) and hit control-D to signal end-of-input on STDIN. For "clean" operation, I'd write it like this:

    #!/usr/bin/perl use strict; use warnings; my $dir = '/etc'; my $prompt = ( -t ) ? 'Enter pattern> ' : ''; print $prompt; while ( my $pattern = <STDIN>) { $pattern =~ s/\s+$//; last unless length( $pattern ); my @matched = eval { grep { /$pattern/ } glob "$dir/*"; }; print "Error: $@" if $@; print join( "\n", @matched, $prompt ); }
    That relies on the "special" behavior of the file-input operator (angle brackets around a file handle) when used as the conditional portion of a "while" statement: the result is false (the loop exits) when the input operator returns "undef" (due to an end-of-file condition). See the "I/O Operators" section of the "perlop" man page (perl operators).

    My version also checks whether input is coming from a terminal (as opposed to a pipe), and prints "Enter pattern >" only in that case (so that the output with pipeline usage is not contaminated by the prompting text).

    I'm tempted to add $pattern =~ s/^\s+//; as well, given that I don't expect any file names in /etc to start with white space, and when reading from a keyboard, it's not unlikely to get initial as well as final spaces that are typed in by mistake.

    Update: It's definitely worthwhile to read the more careful explanation in kcott's reply later in this thread (++ to that).

Re: Can a defined value be of zero length?
by kcott (Archbishop) on Apr 20, 2014 at 05:55 UTC

    G'day j0se,

    You're quite correct in noticing that there's something not-quite-right about that code; however, I believe you're asking the wrong questions.

    My understanding of the intent of that code is to keep processing user input while the user enters patterns. When the user enters no pattern, i.e. just hits the Enter key (or equivalent), then processing should stop.

    Take a look at each of these:

    • perlsyn: Truth and Falsehood: note all the values which are considered to be FALSE.
    • defined: note that this returns a boolean value (which will always be TRUE unless its argument evaluates to undef).
    • length: note that this accepts undef as an argument.

    So, if the user just hits the Enter key, $pattern is assigned "\n" and, after the chomp, it will have the defined, FALSE value of "". The defined $pattern is redundant because it will always be TRUE. Instead of asking:

    "why would I need to check for the length of the string? Is it not enough to check for the "definedness"?"

    A better question might be the reverse of that:

    "Why would I check for definedness? Is it not enough to check for length?"

    And, in this case, the answer would be: "Yes, checking for length is sufficient."

    It's often useful to start a series of chained boolean tests with defined $whatever and as it both short-circuits any further tests (if FALSE) and avoids (potentially copious) "uninitialized value" warnings. In this particular instance, defined is always TRUE and, therefore, never short-circuits; and length accepts undef as an argument without issuing a warning.

    Using length in a test is often used to differentiate the FALSE value "0" (which is valid in some context) from the FALSE value "" (which is invalid in the same context).

    [Completely off-topic: I noticed in your home node that you're keeping a history of your Monk levels. You have "unknown" against "Initiate"; you start at that level when you first register so you can fill that in with 2011-04-10. See Voting/Experience System.]

    -- Ken

        "Have you considered ikegami's answer ..."

        The length v5.10.1 documentation doesn't specifically mention undef but the length v5.12.0 documentation does. (I can't find any mention of this change in any of the deltas for those versions.)

        I'm not in a position to test that (I have several versions availble but 5.12.3 is the earliest); however, assuming that's correct, using defined before length would probably be a good idea if using one of those earlier versions.

        -- Ken

Re: Can a defined value be of zero length?
by Anonymous Monk on Apr 19, 2014 at 09:09 UTC

    Can a defined value be of zero length?

    Yes it can

Re: Can a defined value be of zero length?
by Laurent_R (Canon) on Apr 19, 2014 at 11:36 UTC
    I guess you could almost rewrite your test:
    last unless $pattern;
    except that it would return a different result if the user input is 0 or "0".
Re: Can a defined value be of zero length?
by Anonymous Monk on Apr 19, 2014 at 12:47 UTC
    An empty string is defined but is not true.
Re: Can a defined value be of zero length?
by Anonymous Monk on Apr 19, 2014 at 23:33 UTC

    To answer the why part of your question:

    This code was maybe written in this way by the original coder because he/she got used to the pattern of testing a value for definedness before using it in order to avoid the "Use of uninitialized value" warning:

    $ perl -wMstrict -e 'my $x; print length $x' Use of uninitialized value in print at -e line 1. $ perl -wMstrict -e 'my $x; print length $x if defined $x' $

    or:

    $ perl -wMstrict -e 'my $x; print "yes" if $x=~/foo/' Use of uninitialized value $x in pattern match (m//) at -e line 1. $ perl -wMstrict -e 'my $x; print "yes" if defined $x && $x=~/foo/' $

    However, in this particular case, the test for definedness is not needed:

    $ perl -wMstrict -e 'my $x; print "yes" if defined $x && length $x' $ perl -wMstrict -e 'my $x; print "yes" if length $x' $

    This is because the length function is being used in a boolean context, and whether it returns 0 or undef doesn't matter since they are both evaluated as a false value, see Truth and Falsehood.

      However, in this particular case, the test for definedness is not needed:

      Only since 5.12. Many people still use 5.8 and 5.10.

Re: Can a defined value be of zero length?
by BillKSmith (Monsignor) on Apr 19, 2014 at 23:20 UTC
    Consider using a prompt module. (Untested)
    use strict; use warnings; use IO::Prompt::Hooked; my %options = ( message => 'Enter Pattern> ', validate => sub {eval {qr /$_[0]/}; return $@}, error => "Invalid Pattern\n", escape => qr/^\s*$/, ); my $dir = '/etc'; while (my $pattern = prompt %options) { my @matched = grep { /$pattern/ } glob "$dir/*"; do{ local $, = "\n"; print "@matched\n";}; }
    Bill

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1082874]
Approved by Not_a_Number
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (5)
As of 2024-03-30 05:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found