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

I seem to recall I saw a post about this but my (brief) searching couldn't turn it up. What I'm trying to do is stringify undef to 0. I know undef is treated as 0 in a numeric context, but in a string context it's treated as ''. I'd like for it to appear as 0.
my $foo = undef; print "\$foo = $foo";
Prints "$foo = ". I'd like it to print "$foo = 0". Thoughts/suggestions?

Update: If perhaps I didn't make myself clear, what I was looking for was some way to make undef 0 for every single occurence in the script without changing anything, so no adding "||0" or "defined $x?0:1" tests and stuff. Least effort and all that.

Replies are listed 'Best First'.
Re: Stringifying undefs
by esskar (Deacon) on Mar 02, 2004 at 00:49 UTC
    my $foo = undef; print "\$foo = " . ($foo || 0);
      Or, if you have warnings turned off:
      print "\$foo = " . ($foo + 0);
        use warnings; my $foo = undef; print "\$foo = " . (++$foo-1);
Re: Stringifying undefs
by PodMaster (Abbot) on Mar 02, 2004 at 01:13 UTC
Re: Stringifying undefs
by BrowserUk (Patriarch) on Mar 02, 2004 at 01:17 UTC

    You could play tricks with tie -- I'm not advocating it, but it is a possibility depending upon your purpose.

    { package Undef; sub TIESCALAR{ bless \pop, 'Undef';} sub STORE{ $$_[0] = $_[1]; } sub FETCH{ defined $$_[0] ? $$_[0] : 0 } }; tie $x, 'Undef'; $x = 0; print "'$x'"; '0' $x = ''; print "'$x'"; '' $x = undef; print "'$x'"; '0'

    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail

      That can help, but you're probably have to redefine the builtins undef and return because tieing evrything to Undef by hand is not easier then just writing ||0 everywhere.

      This, however won't help at all if BUU gets the undefs from uninitialized hash or array elements. In that case, you should probably create a tied array/hash that gives 0 for uninitialized elements. (Let me note that you can set what a hash returns instead of an uninitialized element in ruby.)

Re: Stringifying undefs
by Roger (Parson) on Mar 02, 2004 at 01:15 UTC
    my $foo = undef; printf "\$foo = %d", $foo;

Re: Stringifying undefs
by halley (Prior) on Mar 02, 2004 at 17:23 UTC
    But undef isn't zero. Zero is a defined value.

    In C, #define NULL ((void*)0). In C++, #define NULL (0). In Perl, zero is a number and undef is a completely different scalar concept.

    There are many levels of truth in Perl, unlike those other languages. There's non-zero. There's non-empty. There's defined. And the opposite of all of these is undef. (There's even the concept of not existing, which is even less than undef.)

    You can have a hash key of '0' and a different hash key of '', even though both are evaluated as "false" when used in a condition. However, you can't have a hash key of undef. Why? Because undef isn't a string, just like it isn't a number.

    In short, you will have to change your code to accept these two different values. Or say no warnings; in blocks where you want Perl to read your mind without complaining. But don't expect the computer to read your mind so well as to assume you want '0' when you say undef.

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

      But undef isn't zero. Zero is a defined value.
      I don't care! I want them to appear the same.
      But don't expect the computer to read your mind so well as to assume you want '0' when you say undef.
      Obviously the computer isn't reading my mind, otherwise I wouldn't have posted this node. I wanted a method to tell the computer to stringify undef to 0.
        If "understanding Perl" isn't a choice, then it looks like you've got three choices.
        • Modify your application where you meant zero but have undef.
        • Use a hack like redefining undef via some Tie method, for those regions of your application where it's important.
        • Find something other than Perl to do your work.

        I mean, not to be rude or anything, but have you considered that there's a LOT of Perl code out there which would break badly if undef and zero were the same concept?

        If you're using any modules in your application, they're going to be hosed. If your code is so insular that you're not using other people's modules, then it should be pretty straightforward to rewrite the code so it agrees with such fundamental Perl values.

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

Re: Stringifying undefs
by bageler (Hermit) on Mar 02, 2004 at 02:36 UTC
    I see a golf game ;) this one only goes for it if it's truly undefined
    perl -e '$_=shift;print(defined$_?$_:0)'
    this one is shorter but also matches an empty string
    perl -e '$_=shift;print(/^$/?0:$_)'
Re: Stringifying undefs
by bunnyman (Hermit) on Mar 02, 2004 at 18:06 UTC
    use Acme::DWIM;
Re: Stringifying undefs
by bunnyman (Hermit) on Mar 02, 2004 at 22:36 UTC

    I was hoping that this might be done using the "overload" module, but couldn't make it work. You can stringify a blessed reference into anything you like, but we know that "undef" is not a blessed reference so that doesn't help. Then I came up with this:

    perl -e "BEGIN{use overload; overload::constant( integer => sub{ return 'forty two' }) } print 42"

    And that's not what you wanted, but it's pretty cool, huh? The problem is that overload::constant only works with actual constants, not undef values.

Re: Stringifying undefs
by DrHyde (Prior) on Mar 03, 2004 at 08:43 UTC
    I thought you might be able to do something with overload::constant but it appears that you can't use this to overload undefs. If you want to investigate further, you might want to take a look at the source for Scalar::Properties, although I doubt you'll have much luck.