summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul "LeoNerd" Evans <leonerd@leonerd.org.uk>2021-11-20 16:40:59 +0000
committerPaul Evans <leonerd@leonerd.org.uk>2021-11-29 10:35:46 +0000
commit6a2e756f8693f753bad68e1827d8eee014636c86 (patch)
treedc1908e352075eaf47d2e34f8babff880ec18dd6 /lib
parent2a98b8cbbc6f75b5aaefb10acc4da4427359fcea (diff)
downloadperl-6a2e756f8693f753bad68e1827d8eee014636c86.tar.gz
Add a builtin:: namespace, with true/false/isbool
This finishes the perl-visible API required for RFC 0008 https://github.com/Perl/RFCs/blob/master/rfcs/rfc0008.md It also begins the "builtin::" namespace of RFC 0009 https://github.com/Perl/RFCs/blob/master/rfcs/rfc0009.md
Diffstat (limited to 'lib')
-rw-r--r--lib/builtin.pm102
-rw-r--r--lib/builtin.t78
2 files changed, 180 insertions, 0 deletions
diff --git a/lib/builtin.pm b/lib/builtin.pm
new file mode 100644
index 0000000000..461f7ca5fe
--- /dev/null
+++ b/lib/builtin.pm
@@ -0,0 +1,102 @@
+package builtin 0.001;
+
+use strict;
+use warnings;
+
+# All code, including &import, is implemented by always-present functions in
+# the perl interpreter itself.
+# See also `builtin.c` in perl source
+
+1;
+__END__
+
+=head1 NAME
+
+builtin - Perl pragma to import built-in utility functions
+
+=head1 SYNOPSIS
+
+ use builtin qw( true false isbool );
+
+=head1 DESCRIPTION
+
+Perl provides several utility functions in the C<builtin> package. These are
+plain functions, and look and behave just like regular user-defined functions
+do. They do not provide new syntax or require special parsing. These functions
+are always present in the interpreter and can be called at any time by their
+fully-qualified names. By default they are not available as short names, but
+can be requested for convenience.
+
+Individual named functions can be imported by listing them as import
+parameters on the C<use> statement for this pragma.
+
+=head2 Lexical Import
+
+This pragma module creates I<lexical> aliases in the currently-compiling scope
+to these builtin functions. This is similar to the lexical effect of other
+pragmas such as L<strict> and L<feature>.
+
+ sub classify
+ {
+ my $sv = shift;
+
+ use builtin 'isbool';
+ return isbool($sv) ? "boolean" : "not a boolean";
+ }
+
+ # the isbool() function is no longer visible here
+ # but may still be called by builtin::isbool()
+
+Because these functions are imported lexically, rather than by package
+symbols, the user does not need to take any special measures to ensure they
+don't accidentally appear as object methods from a class.
+
+ package An::Object::Class {
+ use builtin 'true', 'false';
+ ...
+ }
+
+ # does not appear as a method
+ An::Object::Class->true;
+
+ # Can't locate object method "true" via package "An::Object::Class"
+ # at ...
+
+=head1 FUNCTIONS
+
+=head2 true
+
+ $val = true;
+
+Returns the boolean truth value. While any scalar value can be tested for
+truth and most defined, non-empty and non-zero values are considered "true"
+by perl, this one is special in that L</isbool> considers it to be a
+distinguished boolean value.
+
+This gives an equivalent value to expressions like C<!!1> or C<!0>.
+
+=head2 false
+
+ $val = false;
+
+Returns the boolean fiction value. While any non-true scalar value is
+considered "false" by perl, this one is special in that L</isbool> considers
+it to be a distinguished boolean value.
+
+This gives an equivalent value to expressions like C<!!0> or C<!1>.
+
+=head2 isbool
+
+ $bool = isbool($val);
+
+Returns true when given a distinguished boolean value, or false if not. A
+distinguished boolean value is the result of any boolean-returning builtin
+function (such as C<true> or C<isbool> itself), boolean-returning operator
+(such as the C<eq> or C<==> comparison tests or the C<!> negation operator),
+or any variable containing one of these results.
+
+=head1 SEE ALSO
+
+L<perlop>, L<perlfunc>, L<Scalar::Util>
+
+=cut
diff --git a/lib/builtin.t b/lib/builtin.t
new file mode 100644
index 0000000000..003efd5ff2
--- /dev/null
+++ b/lib/builtin.t
@@ -0,0 +1,78 @@
+#!./perl
+
+BEGIN {
+ chdir 't' if -d 't';
+ require './test.pl';
+ set_up_inc('../lib');
+}
+
+use strict;
+use warnings;
+
+# booleans
+{
+ use builtin qw( true false isbool );
+
+ ok(true, 'true is true');
+ ok(!false, 'false is false');
+
+ ok(isbool(true), 'true is bool');
+ ok(isbool(false), 'false is bool');
+ ok(!isbool(undef), 'undef is not bool');
+ ok(!isbool(1), '1 is not bool');
+ ok(!isbool(""), 'empty is not bool');
+
+ my $truevar = (5 == 5);
+ my $falsevar = (5 == 6);
+
+ ok(isbool($truevar), '$truevar is bool');
+ ok(isbool($falsevar), '$falsevar is bool');
+
+ ok(isbool(isbool(true)), 'isbool true is bool');
+ ok(isbool(isbool(123)), 'isbool false is bool');
+}
+
+# imports are lexical; should not be visible here
+{
+ my $ok = eval 'true()'; my $e = $@;
+ ok(!$ok, 'true() not visible outside of lexical scope');
+ like($e, qr/^Undefined subroutine &main::true called at /, 'failure from true() not visible');
+}
+
+# lexical imports work fine in a variety of situations
+{
+ sub regularfunc {
+ use builtin 'true';
+ return true;
+ }
+ ok(regularfunc(), 'true in regular sub');
+
+ my sub lexicalfunc {
+ use builtin 'true';
+ return true;
+ }
+ ok(lexicalfunc(), 'true in lexical sub');
+
+ my $coderef = sub {
+ use builtin 'true';
+ return true;
+ };
+ ok($coderef->(), 'true in anon sub');
+
+ sub recursefunc {
+ use builtin 'true';
+ return recursefunc() if @_;
+ return true;
+ }
+ ok(recursefunc("rec"), 'true in self-recursive sub');
+
+ my $recursecoderef = sub {
+ use feature 'current_sub';
+ use builtin 'true';
+ return __SUB__->() if @_;
+ return true;
+ };
+ ok($recursecoderef->("rec"), 'true in self-recursive anon sub');
+}
+
+done_testing();