Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re: How to get 0 to initialize a value

by Marshall (Canon)
on Apr 30, 2019 at 21:36 UTC ( [id://1233207]=note: print w/replies, xml ) Need Help??


in reply to How to get 0 to initialize a value

Hi Lady_Aleena!,

I think others have done a great job of addressing the central coding issue.
This post is in part a reaction to your statement: I can't simply add a +0 to it. I hope that I can clarify why you might want to +0 - that answer has nothing to do with "definedness", but might be interesting for you to know.

In Perl, a variable starts "life" as undefined. "my $x;" means that x is created (memory allocated), but has no value at all associated with it. It does not have a zero numeric value or an empty string or anything else - it has no value whatsoever. Zero is a completely fine and valid value. What "0" means is very well defined.

In Perl, a variable is not just a single memory location. There is a data structure associated with that variable containing a number of properties. When you assign a value to a Perl variable, it gets a string value. If that variable is then later used in a numeric way, Perl will create a numeric value for that variable. This of course is done so that further math calculations with that variable are WAY, WAY faster. For the most part this "magic" is completely transparent (except of course when it is not!).

I wrote some code that illustrates some of the main points. It is difficult in these examples to anticipate every possible scenario. But I think the code makes the main points.

Below in the first example, $string starts out with a string of characters, "00021". This what will happen when you read text DATA as you have done. One way to remove the leading zero'es is with a regex. That is completely fine.

Another way to "delete the leading zero'es" is to use $string in a math operation. The seemingly nonsensical operation of adding zero to $string does that. Internally, Perl now knows that $string is a "number". When you print it, there are no leading zeroes. Perl is using the numeric value for that variable instead of the string value.

There a certain types of data structures that I work with where +0 is a good idea because I'm going to use this value mathematially anyway. This also has the benefit (nor not), depending upon how you look at it of causing a run time error if the $string is not numeric. I show that as example 3 below. Perl will happily do "the best it can", but will report a run time warning in this situation (with use warnings;).

As it turns out, there is one very special case of a non-numeric string that will not produce a warning when used in math! Hard coded into Perl is the exception: "0 but true". That string will evaluate to numeric 0 when used in math, but will also evalue to "true" if that string is tested in a logical context (if ($string){}). Normally "0" evaluates to "false" in a logical operation.

There are certain situations where this behaviour is very useful. For example in the Perl DBI, I do an "SQL update" and I want to know a) did the command work? and b) how many rows were affected? The Perl DBI will return a single value of 0E0 if the command worked (logically true), but zero rows were affected. (0*10**0 = 0*1 = 0).

Starting in Perl 5.10, the // operator was introduced. This operator tests for "definedness".

I show 2 examples of how to set a variable to be some defined value if it is not currently defined. This is useful if say you run a regex to capture some match and that match does not succeed. Rather than some if logic perhaps with the ternary operator, you can just code: $potental_match //= ''; to cover a case where the regex failed to find the $potental_match and set that variable to a default value. I personally recommend the Perl 5.10 coding style because the science of computer programming has shown that any statement with an "if" in it is way, way more likely to contain an error than one without an if. This syntax is clear and works efficiently.

Hope this helped!

#!/usr/bin/perl use strict; use warnings; my $string = "00021"; $string=~ s/^0*//; # remove leading zero'es print "$string\n"; # prints: 21 $string = "00021"; $string += 0; # converts string to a numeric value print "$string\n"; # prints: 21 $string = "00021scores"; #$string += 0; # Warning: Argument "00021scores" isn't numeric i +n addition (+) print "$string\n"; # prints: 21 $string = "0 but true"; $string += 33; # Ha! A Perl special case! no warning! print "$string\n"; # prints: 33 $string = "0E0"; # "better" way for a "logically true but zero valu +e" $string += 33; # print "$string\n"; # prints: 33 my $nothing; #print "$nothing\n"; # Use of uninitialized value $nothing in concaten +ation (.) or string $nothing //= ''; # set $nothing to '' if it was undefined, else no + operation. print "$nothing\n"; # orint is ok, now.. my $nothing2; $nothing2 = '' if !defined $nothing2; # pre Perl 5.10 print "$nothing2\n";
Update:
As far as your code goes, I personally find this ternary within a ternary to be not easy to understand - that means error prone to write and error prone to read. A much more wordy if..elsif..else will compile to the same thing, and probably easier to understand and also for you to see that "undef" is a possible outcome!

Sometimes maximum performance is not needed. Just as one possibility, See the code below. Slightly slower because both regex expressions will be run for all cases, but I personally find the lengthier code easy to understand at a glance.

my $first_type = $first_book =~ /^M/ ? 'major' : $first_book =~ /^m/ +? 'mentioned' : undef; #could be coded as: my $first_type = 'major' if $first_book =~ /^M/; $first_type = 'mentioned' if $first_book =~ /^m/; $first_type //= 'unknown';

Replies are listed 'Best First'.
Re^2: How to get 0 to initialize a value
by Fletch (Bishop) on May 01, 2019 at 14:19 UTC

    Perl Best Practices (chapter 6; don't have dead tree version handy so no clue on a page number) recommends laying chained ternary expressions out as a table. If you squint it almost looks haskelly.

    # Name format... # Salutation... my $salute = $name eq $EMPTY_STR ? 'Dear Custome +r' : $name =~ m/ \A((?:Sir|Dame) \s+ \S+) /xms ? "Dear $1" : $name =~ m/ (.*), \s+ Ph[.]?D \z /xms ? "Dear Dr $1" : "Dear $name" + ;

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re^2: How to get 0 to initialize a value
by Lady_Aleena (Priest) on May 01, 2019 at 19:34 UTC

    Thank you for your very thought out responce, Marshall. I would love to use Perl 5.10; however, my ISP uses CPanel, and the CPanel version they have uses Perl 5.8.8 STILL. To say I am frustrated is putting it mildly. I am writing Dark Age Perl. So, I do things the long way around most of the time when I write Perl, except when I am writing Perl just for myself, then I can use 5.20.2 because that is what Debian Jessie comes with.

    Bad data, and bad me for not double checking, is to blame for my problem. I fixed it now.

    Again thank you for your time and effort.

    No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
    Lady Aleena
      Hi Lady_Aleena!

      Thank you for your kind words. I was trying to help.

      As far as Perl versions goes, it is possible to install your own version of Perl even if the system default version is 5.8. I do believe that a system Perl 5.8 is still common. Perl has become part of the unix "biosphere" and is assumed to be there for the O/S to do its job. I can understand why coding to 5.8 makes sense for programs needed by the O/S. Tackling the problem of "user versions of Perl" requires another thread.

      Perl 5 is like an evolving biological organism. It morphs and adapts. However, not every new gizmo that shows up in the latest release of Perl version is worthy of use in production code. I played with the "smart match" operator and decided that it was too smart for me - I couldn't be sure exactly what it was going to do. Maybe the ambiguities of that operator have been worked out or not? In any event, I can write a lot of code without needing it.

      Some new Perl features like the "//" operator make a lot of sense because it is so clearly different than the "||" operator. I find some features like: say "xyz"; to be goofy and completely unnecessary. Perl is not Python.

      Hang in there, Perl is a great language.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (3)
As of 2024-04-19 21:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found