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

If you want to delete a portion of a string using the four-arg version of substr, this works, but issues a warning:

$s = 'fred';; substr $s, 1,2,undef;; Use of uninitialized value in substr at (eval 7) line 1, <STDIN> line +2. print $s;; fd

The warning is easily avoided by using '' instead of undef, but that seems a little unperlish to me?


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
RIP an inspiration; A true Folk's Guy

Replies are listed 'Best First'.
Re: Use of uninitialized value in substr
by toolic (Bishop) on May 03, 2010 at 12:48 UTC
    Another way to avoid the warning is to locally disable warnings within a block. Maybe more Perlish:
    use strict; use warnings; my $s = 'fred';; { no warnings; substr $s, 1,2,undef;; } print $s;;

    Update: BrowserUk is correct ... I am not licensed to assess if one solution is more Perlish than another. The judge will instruct the jury to ignore that remark :)

      Hm. I'm not sure I'd call having to wrap every use of substr in a no warnings block, more perlish. I'd just go with '' and have done with it.

      It just strikes me that as substr is a built-in, it could accept undef as a legitimate parameter.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        It does. Some builtins just warn when used with undef, but you requested that yourself (by typing use warnings;). So what?

        Inserting an undef null-string is basically the same as interpolating an undefined variable into a string - do you think that shouldn't warn either?

        It just strikes me that as substr is a built-in, it could accept undef as a legitimate parameter.
        Actually, it's only build-ins (be them functions or operators) that trigger this warnings. Which you have to actually enable to see them.

        Why shouldn't this warn, but any of the following should:

        $x = 3 + undef; printf "%s", undef; undef =~ /./;
        The warning is to catch cases like:
        $x = expression unexpectedly returning undef. substr $y, 1, 2, $x;
        One could argue that using a literal undef shouldn't trigger the warning (after all, then the programmer is explicit), but I don't think that information is easily available at the moment the warning is triggered. And the programmer may as well write "" or 0 anyway, saving some keystrokes.

        Then turn off just this warning. It causes more problems than it solves.

        use warnings; no warnings 'uninitialized';

        In this particular case though using '' seems cleaner.

        Jenda
        Enoch was right!
        Enjoy the last years of Rome.

Re: Use of uninitialized value in substr
by ikegami (Patriarch) on May 03, 2010 at 15:32 UTC

    but that seems a little unperlish to me?

    I don't know what you mean. Except for the LHS of .=, I expect Perl to warn me when concatenating undef to a string. Here is another example of it:

    use strict; use warnings; my $s = 'fred'; $s = substr($s,0,1) . undef . substr($s,3);
    Use of uninitialized value in concatenation (.) or string at a.pl line + 4.
      I expect Perl to warn me when concatenating undef to a string.

      This is not about " concatenating undef to a string.". Though even in your unrealistic example, you've explicitly chosen to do that--as dumb as it is--so why should you expect or want a warning. Yes, you could suppress it, but why should you have to for something that could not possibly by "by accident".

      The real question is about making explicit undef semantically different from indirect undef; and therefore making it more powerful, and useful.

      The consensus, to my surprise, is that isn't useful. I think that's at least a premature judgement, if not outright wrong, but I'm insufficiently enamoured with the notion to argue the case further. Which is why I made this 'testing of the waters' post, a SoPW rather than a meditation.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        This is not about " concatenating undef to a string.".

        That's exactly what happens to the 4th arg of substr.

        Yes, you could suppress it, but why should you have to for something that could not possibly by "by accident".

        eh? Of course you can pass an undefined value to substr by accident.

        The real question is about making explicit undef semantically different from indirect undef

        ah! There wasn't even an allusion to this. It's not even an existing concept in Perl as far as anyone is concerned. (Yes, I'm aware there's an instance where literal undef is special in an obscure and unused usage of a builtin, but it's not info I keep in my mind.)

        No thanks for this feature. The following come to mind:

        • It's a solution in search of a problem
        • It adds magic to avoid clear, concise code.
        • It adds a whole new type of variable with high cost and low gains.
        • It adds inconsistencies to the warning system.
        • It adds inconsistencies to substr.

        It's not one of those cases where I can'tcan provide concrete explanation or example. It just reeks of trouble.

        Update: Spelled out some of the reasons.

      I concur. It seems perfectly reasonable for the warning to appear when passing undef (literal or via variable) - '' ought to be used when you want the replacement to be an empty string. For the record, the documentation states:
      An alternative to using substr() as an lvalue is to specify the replacement string as the 4th argument.
      Nothing in there about undef being recognized as a warning-free shortcut for an empty string.
Re: Use of uninitialized value in substr
by shmem (Chancellor) on May 03, 2010 at 21:28 UTC
    The warning is easily avoided by using '' instead of undef, but that seems a little unperlish to me?

    I totally agree with you. Why should perl complain if I explicitly state undef ? -

    Use of uninitialized value in substr at (eval 7) line 1, <STDIN> line +2.

    makes me think "Yes, silly. I know. I put it there on purpose. I wrote that. It's nothing you calculated" which is pretty close to an insult.

    An explicit undef is seen by the compiler, and since the compiler does flip warning bits, it should do that for explicit undef.

    Sometimes it does:

    qwurx [shmem] ~ > perl -le 'print "foo bar ", "baz", ^@^ , " niente"' Useless use of bitwise xor (^) in void context at -e line 1. Useless use of a constant in void context at -e line 1. foo bar baz qwurx [shmem] ~ > perl -le 'print "foo bar ", "baz", ^@^ , undef' Useless use of bitwise xor (^) in void context at -e line 1. foo bar baz qwurx [shmem] ~ > perl -le 'print "foo bar ", "baz", ^@^ , ""' Useless use of bitwise xor (^) in void context at -e line 1. Useless use of a constant in void context at -e line 1. foo bar baz

    The 'useless use of a constant' warning goes away using undef and reappears using an empty string - "which I did write, silly." Ah well... ;-)

    And I also agree that undef for substr as per your example expresses the intended purpose far better than using an empty string. But that's debatable, and maybe the right place to do that is over there at p5porters. Monasteries gather dogmas...

      since the compiler does flip warning bits

      I know it's off topic, but could you give an example of where the compiler flips warning bits or suppresses a warnings? I can't think of any.

      Sometimes it does

      undef() never gives a warning in void context. It's not an example of the compiler messing with the warning bits. It probably should warn if it's in void context and has no args, but it has nothing to do with flipping warning bits. The current implementation probably can't handle the "and has no args" part trivially.

      An explicit undef is seen by the compiler, and since the compiler does flip warning bits, it should do that for explicit undef.

      Your suggested implementation wouldn't work for a number of reasons (substr is already compiled. substr has more than one argument and the warning bits apply to all of them), but it doesn't mean it's not possible. In fact, I think it's quite easy to implement by having the parser convert undef to '' (like it converts while (<>) to while (defined($_ = <>))).

Re: Use of uninitialized value in substr
by chromatic (Archbishop) on May 03, 2010 at 19:22 UTC

    How many other ops do you know which grovel through the optree at runtime to find out the type of a child op in order to perform different behaviors?

      But there is no need for ops to "grovel through the optree at runtime".


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        While his "at runtime" is a straw man, it's not as simple as you imply it is. A lot more than undef returns PL_sv_undef. For example, `foo` (that you insisted is completely unrelated to undef) also returns PL_sv_undef.
        #! perl -slw use 5.010; use strict; use Inline C => Config => BUILD_NOISY => 1; use Inline C => <<'END_C', NAME => 'uCmp', CLEAN_AFTER_BUILD => 0; bool uCmp( SV* t ) { return (bool)( t == (&PL_sv_undef) ); } END_C print 'explicit undef: ', uCmp( undef ) ? 1 : 0; print '`foo`: ', uCmp( scalar(`foo`) ) ? 1 : 0; __END__ explicit undef: 1 Can't exec "foo": No such file or directory at a.pl line 14. `foo`: 1