Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

Defining, Testing and Documenting Perl?

by LanX (Archbishop)
on Dec 23, 2019 at 17:03 UTC ( #11110557=perlmeditation: print w/replies, xml ) Need Help??


I started to write a test script for "Boolean Operators" with and w/o "Short-Circuit" in Perl.

And quickly found me needing to define and test "Truthiness" in Perl.

(Wait ... "0 but true" is false? Remembered it differently ;-)

And now I find myself obliged to also define "Contexts", because an empty list is also false.

And "Data Types", because internally it's more difficult, than just Scalar, Array and Hash.

It's a lot of work, but in the end it could help in many corners when done correctly:

  • Regression testing between Perl versions
  • Leading to a proper language definition
  • Bottom up documenting the language in POD
  • Helping to test cross implementations in other languages like in JS
Properly done means that it needs to be axiomatic, i.e. higher level tests need to only use features proven in lower levels.

Like so often, after a first success I find myself a bit stuck in the big picture.

I'll throw in my first approach as is for meditation.

There is a lot to be criticized, but my normal perfectionism is too risky and might lead to a never release cycle.


Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

use strict; use warnings; use Data::Dump qw/pp dd/; use Scalar::Util qw/isdual/; use Test::More; =head1 Boolean Operations in Perl =head2 True and False values Perl has no boolean datatype but a "boolean context" where other values evaluate to true or false. Operands can be literal values like depending on context. - strings - numbers Lists are converted to scalars Perl variables have 3 main datatypes: Scalars, Arrays and Hashes. The boolean context is just a specialized scalar context and the literal empty list C<()> evaluates to false. Arrays and Hashes are false iff they are empty. Scalar values are internally represented - strings - integers - float (double precission) - references/objects - undefined But Perl allows to use them all interchangabliy by casting them automa +tically. 1. Literal "nothing" is always false - C<undef> in scalar context - empty list, either implicit C<return;> or explicit C<()> NB: a non-empty list is always true, even if the elements are false like in C<return undef> 2. The neutral element of every internal datatype is FALSE: - i.e. all literal zeroes for numbers 0, 0.0, 0e0 - the empty string '' - empty arrays and hashes NB: The "0" string is also false, because Perl treats 0 and "0" to be the same scalar. But "0.0" or "0E0" are never false, these are literal notations. 3. References including those blessed to objects are always true. NB: You can treach with C<use overload> to make objects false. =cut =head2 Boolean return values Most Boolean operators like C<!> for C<not> return a "default scalar" as represntative for true and false. These can be easily construted by double negation false := !!0 true := !!1 But so called "Short-circuit Operators" change the control-flow. They return the last evaluated side instead, which is guarantied to be logically correct (later more) =cut my @false = ( !!0, # default 0, 0.0, 0e0, 0e10, "0", # scalar zeroes '', # empty string undef, # undef !!(), # empty list ); # NB: you can fake "false" objects by using =overload= sub is_FALSE { return unless isdual($_[0]) ; my $num = $_[0]; my $str = $_[0]; return ($num == 0) && ($str eq ""); } cmp_ok ( !!0, "==", 0, "!!0 is 0 in numeric context"); cmp_ok ( !!0, "eq", "", "!!0 is '' in string context"); ok ( is_FALSE(!!0)); # anything else is true my @true = ( !!1, # default 1 , "A", "0abc", "0 but true", "0e0", # all strings except "0" \0, [], {}, # refs (including blessed obje +cts) ); cmp_ok ( !!1, "==", 1, "!!1 == 1 in numeric context"); cmp_ok ( !!1, "eq", 1, "!!1 eq 1 in string context"); cmp_ok ( !!1, "eq", '1', "!!1 eq '1' in string context"); for my $x ( @true ) { ok ( $x, "true: ". pp($x) ); } for my $x ( @false ) { ok ( ! $x, "false: ". pp($x) ); } #done_testing(); #exit; =head2 short-circuit operators =cut my @values = (@false, @true); warn pp \@values; for my $x ( @values ) { for my $y ( @values ) { is( ($x || $y), ($x ? $x : $y), "|| " .pp($x,$y) . " => " . pp ($x || $y) ); } } for my $x ( @values ) { for my $y ( @values ) { is( ($x && $y), (!$x ? $x : $y), "&& ".pp($x,$y) . " => " . pp ($x && $y) ); } } for my $x ( @values ) { for my $y ( @values ) { is( ($x // $y), ( (defined $x) ? $x : $y), "// ".pp($x,$y) . " => " . pp ($x && $y) ); } } done_testing();

Replies are listed 'Best First'.
Re: Defining, Testing and Documenting Perl?
by Tux (Abbot) on Dec 23, 2019 at 20:37 UTC

    /me mumbles .oO( ties and overloads )

    Enjoy, Have FUN! H.Merijn

      Fun fact: the Moose "Bool" datatype will accept overloaded objects, but only if they stringify to "", "0", "1" or undef. It doesn't care what they boolify to!

      Other fun fact: the Mouse "Bool" datatype will accept overloaded objects, but only if they boolify to a false value.


      This is why Types::Standard 1.004 abandoned trying to be compatible with Moose and Mouse's definitions of "Bool" and instead just accepts "", "0", "1" and undef, but offers a coercion from other values.

      > mumbles .oO( ties and overloads )

      what's your point?

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        I believe a tied hash can override how it behaves in scalar context, so that an empty hash can return true and a non-empty hash can return false.

        An overloaded object can do various tricky things with regards to how it behaves as a boolean. For example, it could die.

        if ($x || $y) { say "Something was true. What was it?"; say '$x' if $x; say '$y' if $y; } else { say "Neither was true."; }

        It is possible for this to print "Something was true?" but not tell you what was true. This is because $x or $y could be an overloaded object returning true or false at random each time they are checked.

Re: Defining, Testing and Documenting Perl?
by Anonymous Monk on Dec 24, 2019 at 20:19 UTC
    Sorry to say that not one single programming language that has "stood the tests of time" – including, by the way, JavaScript – is immune to this. Programming languages are tools of our trade which usually are developed over many decades. Shit happens – and always will. "Engineer accordingly."
      No idea what you are talking about.

      > Shit ...

      Now I smell!

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

      A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://11110557]
Approved by GrandFather
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (7)
As of 2020-05-27 12:40 GMT
Find Nodes?
    Voting Booth?
    If programming languages were movie genres, Perl would be:

    Results (155 votes). Check out past polls.