Re: type checks

[email protected] (sisyphus) Sat, 3 Jun 2023 22:16:01 +1000
Newsgroups perl.beginners
Message-ID <CADZSBj3uG42R9x1YOvDvUQYW1Sc+P=R1mTPZMAe3yk0aGq5VHQ@mail.gmail.com>
On Sat, Jun 3, 2023 at 6:41 PM Claude Brown <[email protected]>
wrote:

> Interesting.  I’d not used “B” before, so doing a little reading on that
> was fun, plus seeing how you had used it.
>
>
>
> Question: why did you have “is_ok” return 2 and 3, rather than just 1?
>

The way I've coded the "oload_*" subroutines there's a need to know whether
the second arg ($_[1]) is a Math::NumOnly object or a perl scalar.
Having is_ok return 1 for a Math::NumOnly object and a different value for
a valid perl scalar allows those subroutines to make that determination.

Of course, there's no apparent reason that we need to distinguish between
an IV (integer) scalar and an NV (float) scalar - so I could have just
returned "2" for both, rather than "2" for the IV and "3" for the NV.
(The OP's spec mentioned only integer values, and I initially considered
the possibility that there might be a need to distinguish between IVs and
NVs.)

And I must give credit where credit is due:
The B module stuff I used is stolen from:
https://metacpan.org/release/HAARG/Sub-Quote-2.006006/source/t/quotify.t

It has since occurred to me that there's a simpler solution that meets the
OP's spec - one that doesn't involve the creation of a specially designated
module.
Firstly, you just take the declaration of %flags as presented in
Math::NumOnly:
#########################
  use B;
  my %flags;
  {
    no strict 'refs';
    for my $flag (qw(
      SVf_IOK
      SVf_NOK
      SVf_POK
              )) {
      if (defined &{'B::'.$flag}) {
       $flags{$flag} = &{'B::'.$flag};
      }
    }
  }
#########################

However, you alter is_ok() to either return the numeric value of the scalar
(if that scalar satisfies the OP's spec); otherwise the sub croaks:

#########################
sub is_ok {
 die "Undefined value encountered" unless defined $_[0];
  my $val = shift;
  my $flags = flags($val);
  die "Bad value encountered" if $flags =~ /SVf_POK/;
  return $val
     if $flags =~ /SVf_IOK|SVf_NOK/;
  die "Bad value encountered";
}
#########################

Then, in your perl script, instead of doing:
$z = $x + $y;
you do:
$z = is_ok($x) + is_ok($y);

For example, the following code would result is $z being set to 7:
$x = 4;
$y = 3;
$z = is_ok($x) + is_ok($y);

But the following would die:
$x = 4;
$y = '3';
$z = is_ok($x) + is_ok($y);

Similarly, instead of doing:
$x += $y;
you would do:
is_ok($x) += is_ok($y);

and $x would be set to $x * $y if both $x and $y meet the spec; otherwise
the script dies.

Cheers,
Rob