Synopsis 29: Builtin Functions
Author: Rod Adams <rod@rodadams.net>
Maintainer: Larry Wall <larry@wall.org>
Contributions: Aaron Sherman <ajs@ajs.com>
Mark Stosberg <mark@summersault.com>
Date: 12 Mar 2005
Last Modified: 31 Jan 2008
Version: 20
This document attempts to document the list of builtin functions in Perl 6. It assumes familiarity with Perl 5 and prior synopses.
The document is now the official S29. It's still here in the pugs repository temporarily to allow easy access to pugs implementors, but eventually it will be copied over to svn.perl.org. Despite its being "official", feel free to hack on it as long as it's in the pugs space. -law
This document is generated from the pod in the pugs repository under /docs/Perl6/Spec/Functions.pod so edit it there in the SVN repository if you would like to make changes.
In Perl 6, all builtin functions belong to a named package (generally a class or role). Not all functions are guaranteed to be imported into the global package ::*. In addition, the list of functions imported into ::* will be subject to change with each release of Perl. Authors wishing to "Future Proof" their code should either specifically import the functions they will be using, or always refer to the functions by their full name.
After 6.0.0 comes out, global aliases will not be removed lightly, and will never be removed at all without having gone through a deprecation cycle of at least a year. In any event, you can specify that you want the interface for a particular version of Perl, and that can be emulated by later versions of Perl to the extent that security updates allow.
Where code is given here, it is intended to define semantics, not to dictate implementation.
There is no particular difference between an operator and a function, but for the sake of documentation, only functions declared without specifying a grammatical category or with a category of term: (see "Bits and Pieces" in S02) will be described as "functions", and everything else as "operators" which are outside of the scope of this document.
In actual fact, most of the "functions" defined here are multi subs, or are multi methods that are also exported as multi subs. Multi subs are all visible in the global namespace (unless declared with a "my multi"). The assumption is that with sufficiently specific typing on the multis, the user is free to extend a particular name to new types.
From t/spec/S29-type/declarations.t lines 4–29 (no results): (skip)
| # L<S29/"Type Declarations">
|
|
|
| =begin pod
|
|
|
| Test for some type declarations for built-in functions.
|
|
|
| =end pod
|
|
|
| plan 9;
|
|
|
| # Maybe this test should be modified to run with rakudo
|
|
|
| my sub ok_eval1($code) {
|
| #?pugs todo 'feature'
|
| &Test::ok.nextwith(eval($code),$code)
|
| }
|
|
|
| ok_eval1('AnyChar.isa(Str)');
|
| ok_eval1('Char.isa(Str)');
|
| ok_eval1('Codepoint =:= Uni');
|
| ok_eval1('CharLingua.isa(AnyChar)');
|
| ok_eval1('Grapheme.isa(AnyChar)');
|
| ok_eval1('Codepoint.isa(AnyChar)');
|
| ok_eval1('Byte.isa(AnyChar)');
|
| ok_eval1('Byte.isa(Num)');
|
| ok_eval1('subset MatchTest of Item | Junction;');
|
The following type declarations are assumed:
The root class of all "character" types, regardless of level.
This is a subtype of Str, limited to a length of 1 at it's highest supported Unicode level.
The type name Char is aliased to the maximum supported Unicode level in the current lexical scope (where "current" is taken to mean the eventual lexical scope for generic code (roles and macros), not the scope in which the generic code is defined). In other words, use Char when you don't care which level you're writing for.
Subclasses (things that are isa AnyChar):
Yes, Byte is both a string and a number.
The short name for Grapheme is typically Char since that's the default Unicode level. A grapheme is defined as a base codepoint plus any subsequent "combining" codepoints that apply to that base codepoint. Graphemes are always assigned a unique integer id which, in the case of a grapheme that has a precomposed codepoint, happens to be the same as that codepoint.
There is no short name for CharLingua because the type is meaningless outside the scope of a particular language declaration. In fact, CharLingua is itself an abstract type that cannot be instantiated. Instead you have names like CharFrench, CharJapanese, CharTurkish, etc. for instantiated CharLingua types. (Plus the corresponding StrLingua types, presumably.)
subset Matcher of Item | Junction;
Used to supply a test to match against. Assume ~~ will be used against it.
subset KeyExtractor of Code where { .sig === :(Any --> Any) };
subset Comparator of Code where { .sig === :(Any, Any --> Int ) };
subset OrderingPair of Pair where { .left ~~ KeyExtractor && .right ~~ Comparator };
subset Ordering where Signature | KeyExtractor | Comparator | OrderingPair;
Used to handle comparisons between things. Generally this ends up in functions like cmp(), eqv(), sort(), min(), max(), etc., as a $by parameter which provides the information on how two things compare relative to each other.
Note that eqv() and cmp() do almost but not the same thing since with eqv() you don't care if two things are ordered increasing or decreasing but only if they are the same or not. Rather than declare an Equiving type declaration Ordering will just do double duty.
A closure with arity of 2, which for ordering returns negative/zero/positive, signaling the first argument should be before/tied with/after the second. aka "The Perl 5 way".
For equivalence the closure returns either not 0 or 0 indicating if the first argument is equivalent or not to the second.
A closure with arity of 1, which returns the "key" by which to compare. Values are compared using cmp for orderings and eqv for equivalences, which in Perl 6 do different comparisons depending on the types. (To get a Perl 5 string ordering you must compare with leg instead.)
Internally the result of the KeyExtractor on a value should be cached.
A combination of the two methods above, for when one wishes to take advantage of the internal caching of keys that is expected to happen, but wishes to compare them with something other than eqv or cmp, such as <=> or leg.
If a signature is specified as a criterion, the signature is bound to each value and then each parameter does comparisons in positional order according to its type, as modified by its traits. Basically, the system will write the body of the key extraction and comparison subroutine for you based on the signature.
For ordering the list of positional parameter comparisons is reduced as if using [||] but all comparisons do not need to be performed if an early one determines an increasing or decreasing order. For equivalence the list is reduced as if using [&&].
The following are defined in the Any role:
From t/spec/S29-any/eqv.t lines 6–119 (no results): (skip)
| # L<S29/Any/"=item eqv">
|
|
|
| # eqv on values
|
| {
|
| ok (1 eqv 1), "eqv on values (1)";
|
| ok (0 eqv 0), "eqv on values (2)";
|
| ok !(0 eqv 1), "eqv on values (3)";
|
| }
|
|
|
| # Value types
|
| {
|
| my $a = 1;
|
| my $b = 1;
|
|
|
| ok $a eqv $a, "eqv on value types (1-1)";
|
| ok $b eqv $b, "eqv on value types (1-2)";
|
| ok $a eqv $b, "eqv on value types (1-3)";
|
| }
|
|
|
|
|
| {
|
| my $a = 1;
|
| my $b = 2;
|
|
|
| ok ($a eqv $a), "eqv on value types (2-1)";
|
| ok ($b eqv $b), "eqv on value types (2-2)";
|
| ok !($a eqv $b), "eqv on value types (2-3)";
|
| }
|
|
|
| # Reference types
|
| {
|
| my @a = (1,2,3);
|
| my @b = (1,2,3);
|
|
|
| ok (\@a eqv \@a), "eqv on array references (1)";
|
| ok (\@b eqv \@b), "eqv on array references (2)";
|
| #?pugs todo 'bug'
|
| ok !(\@a eqv \@b), "eqv on array references (3)";
|
| }
|
|
|
| {
|
| my $a = \3;
|
| my $b = \3;
|
|
|
| ok ($a eqv $a), "eqv on scalar references (1-1)";
|
| ok ($b eqv $b), "eqv on scalar references (1-2)";
|
| #?pugs todo 'bug'
|
| ok !($a eqv $b), "eqv on scalar references (1-3)";
|
| }
|
|
|
| {
|
| my $a = { 3 };
|
| my $b = { 3 };
|
|
|
| ok ($a eqv $a), "eqv on sub references (1-1)";
|
| ok ($b eqv $b), "eqv on sub references (1-2)";
|
| ok !($a eqv $b), "eqv on sub references (1-3)";
|
| }
|
|
|
| {
|
| ok (&say eqv &say), "eqv on sub references (2-1)";
|
| ok (&map eqv &map), "eqv on sub references (2-2)";
|
| ok !(&say eqv &map), "eqv on sub references (2-3)";
|
| }
|
|
|
| {
|
| my $num = 3;
|
| my $a = \$num;
|
| my $b = \$num;
|
|
|
| ok ($a eqv $a), "eqv on scalar references (2-1)";
|
| ok ($b eqv $b), "eqv on scalar references (2-2)";
|
| ok ($a eqv $b), "eqv on scalar references (2-3)";
|
| }
|
|
|
| {
|
| ok !([1,2,3] eqv [4,5,6]), "eqv on anonymous array references (1)";
|
| #?pugs 2 todo 'bug'
|
| ok !([1,2,3] eqv [1,2,3]), "eqv on anonymous array references (2)";
|
| ok !([] eqv []), "eqv on anonymous array references (3)";
|
| }
|
|
|
| {
|
| ok !({a => 1} eqv {a => 2}), "eqv on anonymous hash references (1)";
|
| ok !({a => 1} eqv {a => 1}), "eqv on anonymous hash references (2)";
|
| }
|
|
|
| {
|
| ok !(\3 eqv \4), "eqv on anonymous scalar references (1)";
|
| #?pugs 2 todo 'bug'
|
| ok !(\3 eqv \3), "eqv on anonymous scalar references (2)";
|
| ok !(\undef eqv \undef), "eqv on anonymous scalar references (3)";
|
| }
|
|
|
| # Chained eqv (not specced, but obvious)
|
| {
|
| ok (3 eqv 3 eqv 3), "chained eqv (1)";
|
| ok !(3 eqv 3 eqv 4), "chained eqv (2)";
|
| }
|
|
|
| # Subparam binding doesn't affect eqv test
|
| {
|
| my $foo;
|
| my $test = -> $arg { $foo eqv $arg };
|
|
|
| $foo = 3;
|
| ok $test($foo), "subparam binding doesn't affect eqv (1)";
|
| ok $test(3), "subparam binding doesn't affect eqv (2)";
|
|
|
| ok !$test(4), "subparam binding doesn't affect eqv (3)";
|
| my $bar = 4;
|
| ok !$test($bar), "subparam binding doesn't affect eqv (4)";
|
| }
|
|
|
our Bool multi sub eqv (Ordering @by, $a, $b) our Bool multi sub eqv (Ordering $by = &infix:<eqv>, $a, $b)
Returns a Bool indicating if the parameters are equivalent, using criteria $by or @by for comparisons. @by differs from $by in that each criterion is applied, in order, until a non-zero (equivalent) result is achieved.
From t/spec/S29-any/cmp.t lines 6–11 (3 √, 0 ×): (skip)
| # L<S29/Any/"=item cmp"> |
| |
√ | is('a' cmp 'a', 0, 'a is equal to a'); |
√ | is('a' cmp 'b', -1, 'a is less than b'); |
√ | is('b' cmp 'a', 1, 'b is greater than a'); |
| |
our Order multi sub cmp (Ordering @by, $a, $b) our Order multi sub cmp (Ordering $by = &infix:<cmp>, $a, $b)
Returns Order::Increase, or Order::Same, or Order::Decrease (which numify to -1, 0, +1 respectively) indicating if paramater $a should be ordered before/tied with/after parameter $b, using criteria $by or @by for comparisons. @by differs from $by in that each criterion is applied, in order, until a non-zero (tie) result is achieved. If the values are not comparable, returns a proto Order object that is undefined.
The following are all defined in the Num role:
API document: Num
Num provides a number of constants in addition to the basic mathematical functions. To get these constants, you must request them:
From t/spec/S29-num/pi.t lines 5–36 (0 √, 6 ×): (skip)
| # L<S29/Num/"Num provides a number of constants"> |
| |
| =begin pod |
| |
| =head1 DESCRIPTION |
| |
| Basic tests for builtin Num::pi |
| |
| =end pod |
| |
| |
| # See also: L<"http://theory.cs.iitm.ernet.in/~arvindn/pi/"> :) |
| my $PI = 3.14159265358979323846264338327950288419716939937510; |
| |
| #?rakudo 6 skip 'eval not implemented' |
× | is_approx((eval("Num::pi "), $PI), |
| "Num::pi"); |
| |
× | is_approx((eval("use Num :constants; pi"), $PI), |
| "pi imported by use Num :constants"); |
| |
× | is_approx((eval("use Num :constants; 3 + pi()"), $PI+3), " |
| 3+pi(), as a sub"); |
| |
× | is_approx((eval("use Num :constants; pi() + 3"), $PI+3), |
| "pi()+3, as a sub"); |
| |
× | is_approx((eval("use Num :constants; 3 + pi"), $PI+3), |
| "3+pi, as a bareword"); |
| |
× | is_approx((eval("use Num :constants; pi + 3"), $PI+3), |
| "pi+3, as a bareword"); |
use Num :constants;
or use the full name, e.g. Num::pi.
From t/spec/S29-num/complex.t lines 36–49 (no results): (skip)
| # L<S29/Num/"=item abs"> |
| # |
| # Test that unpolar() doesn't change the absolute value |
| |
| my $counter = 1; |
| for 1..10 -> $abs { |
| for 1..10 -> $a { |
| my $angle = 2 * $pi * $i / 10; |
| is_approx((abs($abs.unpolar($angle)), $abs ), |
| "unpolar doesn't change the absolute value (No $counter)"); |
| $counter++; |
| } |
| } |
| |
From t/spec/S29-num/abs.t lines 5–35 (8 √, 0 ×): (skip)
| # L<S29/Num/"=item abs"> |
| |
| =begin pod |
| |
| Basic tests for the abs() builtin |
| |
| =end pod |
| |
| for(0, 0.0, 1, 50, 60.0, 99.99) { |
√ | is(abs($_), $_, "got the right absolute value for $_"); |
| #?rakudo skip 'parsefail' |
√ | is(WHAT abs($_), WHAT $_, "got the right data type("~WHAT($_)~") of absolute value for $_"); |
| } |
| for(-1, -50, -60.0, -99.99) { |
√ | is(abs($_), -$_, "got the right absolute value for $_"); |
| #?rakudo skip 'parsefail' |
√ | is(WHAT abs($_), WHAT $_, "got the right data type("~WHAT($_)~") of absolute value for $_"); |
| } |
| |
| for (0, 0.0, 1, 50, 60.0, 99.99) { |
| #?rakudo skip 'parsefail' |
√ | is(.abs, $_, 'got the right absolute value for $_='~$_); |
| #?rakudo skip 'parsefail' |
√ | is(WHAT .abs, WHAT $_, 'got the right data type('~WHAT($_)~') of absolute value for $_='~$_); |
| } |
| for (-1, -50, -60.0, -99.99) { |
| #?rakudo skip 'parsefail' |
√ | is(.abs, -$_, 'got the right absolute value for $_='~$_); |
| #?rakudo skip 'parsefail' |
√ | is(WHAT .abs, WHAT $_, 'got the right data type('~WHAT($_)~') of absolute value for $_='~$_); |
| } |
our Num multi method abs ( Num $x: ) is export
Absolute Value.
From t/spec/S29-num/rounders.t lines 6–49 (no results): (skip)
| # L<S29/Num/"=item floor">
|
| # L<S29/Num/"=item truncate">
|
| # L<S29/Num/"=item ceiling">
|
|
|
| =begin pod
|
|
|
| Basic tests for the round(), floor(), truncate() and ceil() built-ins
|
|
|
| =end pod
|
|
|
| my %tests =
|
| ( ceiling => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 2 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| floor => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, -1 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, -1 ], [ -5.499, -6 ] ],
|
| round => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| truncate => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| );
|
|
|
| #?pugs emit if $?PUGS_BACKEND ne "BACKEND_PUGS" {
|
| #?pugs emit skip_rest "PIL2JS and PIL-Run do not support eval() yet.";
|
| #?pugs emit exit;
|
| #?pugs emit }
|
|
|
| for %tests.keys.sort -> $type {
|
| my @subtests = @(%tests{$type}); # XXX .[] doesn't work yet!
|
| for @subtests -> $test {
|
| my $code = "{$type}($test[0])";
|
| my $res = eval($code);
|
| if ($!) {
|
| #?pugs todo 'feature'
|
| flunk("failed to parse $code ($!)");
|
| } else {
|
| is($res, $test[1], "$code == $test[1]");
|
| }
|
| }
|
| }
|
|
|
our Int multi method floor ( Num $x: ) is export
Returns the highest integer not greater than $x.
From t/spec/S29-num/rounders.t lines 8–49 (no results): (skip)
| # L<S29/Num/"=item ceiling">
|
|
|
| =begin pod
|
|
|
| Basic tests for the round(), floor(), truncate() and ceil() built-ins
|
|
|
| =end pod
|
|
|
| my %tests =
|
| ( ceiling => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 2 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| floor => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, -1 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, -1 ], [ -5.499, -6 ] ],
|
| round => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| truncate => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| );
|
|
|
| #?pugs emit if $?PUGS_BACKEND ne "BACKEND_PUGS" {
|
| #?pugs emit skip_rest "PIL2JS and PIL-Run do not support eval() yet.";
|
| #?pugs emit exit;
|
| #?pugs emit }
|
|
|
| for %tests.keys.sort -> $type {
|
| my @subtests = @(%tests{$type}); # XXX .[] doesn't work yet!
|
| for @subtests -> $test {
|
| my $code = "{$type}($test[0])";
|
| my $res = eval($code);
|
| if ($!) {
|
| #?pugs todo 'feature'
|
| flunk("failed to parse $code ($!)");
|
| } else {
|
| is($res, $test[1], "$code == $test[1]");
|
| }
|
| }
|
| }
|
|
|
our Int multi method ceil ( Num $x: ) is export
Returns the lowest integer not less than $x.
From t/spec/S29-num/rounders.t lines 5–49 (no results): (skip)
| # L<S29/Num/"=item round">
|
| # L<S29/Num/"=item floor">
|
| # L<S29/Num/"=item truncate">
|
| # L<S29/Num/"=item ceiling">
|
|
|
| =begin pod
|
|
|
| Basic tests for the round(), floor(), truncate() and ceil() built-ins
|
|
|
| =end pod
|
|
|
| my %tests =
|
| ( ceiling => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 2 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| floor => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, -1 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, -1 ], [ -5.499, -6 ] ],
|
| round => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| truncate => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| );
|
|
|
| #?pugs emit if $?PUGS_BACKEND ne "BACKEND_PUGS" {
|
| #?pugs emit skip_rest "PIL2JS and PIL-Run do not support eval() yet.";
|
| #?pugs emit exit;
|
| #?pugs emit }
|
|
|
| for %tests.keys.sort -> $type {
|
| my @subtests = @(%tests{$type}); # XXX .[] doesn't work yet!
|
| for @subtests -> $test {
|
| my $code = "{$type}($test[0])";
|
| my $res = eval($code);
|
| if ($!) {
|
| #?pugs todo 'feature'
|
| flunk("failed to parse $code ($!)");
|
| } else {
|
| is($res, $test[1], "$code == $test[1]");
|
| }
|
| }
|
| }
|
|
|
our Int multi method round ( Num $x: ) is export
Returns the nearest integer to $x. The algorithm is floor($x + 0.5). (Other rounding algorithms will be given extended names beginning with "round".)
From t/spec/S29-num/int.t lines 5–81 (no results): (skip)
| # L<S29/Num/"=item truncate">
|
| # truncate and int() are synonynms.
|
| # Possibly more tests for truncate should be added here, too.
|
|
|
| =begin pod
|
|
|
| Basic tests for the int() builtin
|
|
|
| =end pod
|
|
|
| is(int(-1), -1, "int(-1) is -1");
|
| is(int(0), 0, "int(0) is 0");
|
| is(int(1), 1, "int(1) is 1");
|
| is(int(3.14159265), 3, "int(3.14159265) is 3");
|
| is(int(-3.14159265), -3, "int(-3.14159265) is -3");
|
|
|
| is(int(0.999), 0, "int(0.999) is 0");
|
| is(int(0.51), 0, "int(0.51) is 0");
|
| is(int(0.5), 0, "int(0.5) is 0");
|
| is(int(0.49), 0, "int(0.49) is 0");
|
| is(int(0.1), 0, "int(0.1) is 0");
|
|
|
| is(int(-0.999), -0, "int(-0.999) is -0");
|
| is(int(-0.51), -0, "int(-0.51) is -0");
|
| is(int(-0.5), -0, "int(-0.5) is -0");
|
| is(int(-0.49), -0, "int(-0.49) is -0");
|
| is(int(-0.1), -0, "int(-0.1) is -0");
|
|
|
| is(int(1.999), 1, "int(1.999) is 1");
|
| is(int(1.51), 1, "int(1.51) is 1");
|
| is(int(1.5), 1, "int(1.5) is 1");
|
| is(int(1.49), 1, "int(1.49) is 1");
|
| is(int(1.1), 1, "int(1.1) is 1");
|
|
|
| is(int(-1.999), -1, "int(-1.999) is -1");
|
| is(int(-1.51), -1, "int(-1.51) is -1");
|
| is(int(-1.5), -1, "int(-1.5) is -1");
|
| is(int(-1.49), -1, "int(-1.49) is -1");
|
| is(int(-1.1), -1, "int(-1.1) is -1");
|
|
|
| is(int('-1.999'), -1, "int('-1.999') is -1");
|
| is(int('0x123'), 0x123, "int('0x123') is 0x123");
|
| is(int('0d456'), 0d456, "int('0d456') is 0d456");
|
| is(int('0o678'), 0o67, "int('0o678') is 0o67");
|
| #?rakudo: skip 'parsefail'
|
| is(int('3e4d5'), 3e4, "int('3e4d5') is 3e4");
|
|
|
| #?rakudo skip 'parsefail'
|
| {
|
| sub __int( Str $s ) {
|
| if ($s ~~ rx:Perl5/^(-?\d+)$/) { return $0 };
|
| if ($s ~~ rx:Perl5/^(-?\d+)\./) { return $0 };
|
| if ($s ~~ rx:Perl5/^\./) { return 0 };
|
| return undef;
|
| };
|
|
|
| # Check the defaulting to $_
|
|
|
| for(0, 0.0, 1, 50, 60.0, 99.99, 0.4, 0.6,
|
| -1, -50, -60.0, -99.99
|
| ) {
|
| my $int = __int($_);
|
| is(.int, $int, "integral value for $_ is $int");
|
| isa_ok(.int, "Int");
|
| }
|
| }
|
|
|
| # Special values
|
|
|
| #?rakudo 4 skip 'parsefail'
|
| is(int(1.9e3), 1900, "int 1.9e3 is 1900");
|
| #?pugs 3 todo 'bug'
|
| is(int(Inf), Inf, "int Inf is Inf");
|
| is(int(-Inf), -Inf, "int -Inf is -Inf");
|
| is(int(NaN), NaN, "int NaN is NaN");
|
|
|
| #?rakudo emit skip_rest 'parsefail';
|
From t/spec/S29-num/rounders.t lines 7–49 (no results): (skip)
| # L<S29/Num/"=item truncate">
|
| # L<S29/Num/"=item ceiling">
|
|
|
| =begin pod
|
|
|
| Basic tests for the round(), floor(), truncate() and ceil() built-ins
|
|
|
| =end pod
|
|
|
| my %tests =
|
| ( ceiling => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 2 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| floor => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, -1 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, -1 ], [ -5.499, -6 ] ],
|
| round => [ [ 1.5, 2 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -6 ],
|
| [ -0.5, -1 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| truncate => [ [ 1.5, 1 ], [ 2, 2 ], [ 1.4999, 1 ],
|
| [ -0.1, 0 ], [ -1, -1 ], [ -5.9, -5 ],
|
| [ -0.5, 0 ], [ -0.499, 0 ], [ -5.499, -5 ] ],
|
| );
|
|
|
| #?pugs emit if $?PUGS_BACKEND ne "BACKEND_PUGS" {
|
| #?pugs emit skip_rest "PIL2JS and PIL-Run do not support eval() yet.";
|
| #?pugs emit exit;
|
| #?pugs emit }
|
|
|
| for %tests.keys.sort -> $type {
|
| my @subtests = @(%tests{$type}); # XXX .[] doesn't work yet!
|
| for @subtests -> $test {
|
| my $code = "{$type}($test[0])";
|
| my $res = eval($code);
|
| if ($!) {
|
| #?pugs todo 'feature'
|
| flunk("failed to parse $code ($!)");
|
| } else {
|
| is($res, $test[1], "$code == $test[1]");
|
| }
|
| }
|
| }
|
|
|
our Int multi method truncate ( Num $x: ) is export our Int multi method int ( Num $x: ) is export
Returns the closest integer to $x whose absolute value is not greater than the absolute value of $x. (In other words, just chuck any fractional part.) This is the default rounding function used by an int() cast, for historic reasons. But see Int constructor above for a rounded version.
From t/spec/S29-num/exp.t lines 5–30 (0 √, 6 ×): (skip)
| # L<S29/Num/"=item exp"> |
| |
| =begin pod |
| |
| Basic tests for the exp() builtin |
| |
| =end pod |
| |
| #?rakudo 2 skip "is_approx failing" |
× | is_approx((exp(5), 148.4131591025766), 'got the exponent of 5'); |
× | is_approx((exp(0), 1), 'exp(0) == 1'); |
| |
| #?rakudo 2 skip "can't parse complex numbers" |
| # exp with complex arguments |
× | is_approx((exp(1i*pi), -1), 'exp(i pi) == -1'); |
× | is_approx((exp(-1i*pi), -1), 'exp(-i pi) == -1'); |
| |
| #?rakudo skip "can't parse complex numbers" |
| { |
| for 1 .. 20 { |
| my $arg = 2.0 * pi / $_; |
× | is_approx((exp(1i * $arg), cos($arg) + 1i * sin($arg)), 'expi == cos + i sin No. ' ~ $_); |
× | is_approx((exp(1i * $arg) * exp(-1i * $arg), 1), 'exp(ix) * exp(-ix) == 1 No. ' ~ $_); |
| } |
| } |
| #?rakudo emit skip_rest "can't parse complex numbers"; |
our Num multi method exp ( Num $exponent: Num :$base = Num::e ) is export
Performs similar to $base ** $exponent. $base defaults to the constant e.
From t/spec/S29-num/log.t lines 11–15 (no results): (skip)
| # L<S29/Num/"=item log">
|
|
|
| is_approx(log(5), 1.6094379124341003, 'got the log of 5');
|
| is_approx(log(0.1), -2.3025850929940455, 'got the log of 0.1');
|
|
|
our Num multi method log ( Num $x: Num :$base = Num::e ) is export
Logarithm of base $base, default Natural. Calling with $x == 0 is an error.
From t/spec/S29-num/log.t lines 16–45 (no results): (skip)
| # L<S29/Num/"=item log10">
|
|
|
| is_approx(log10(5), 0.6989700043360187, 'got the log10 of 5');
|
| is_approx(log10(0.1), -0.9999999999999998, 'got the log10 of 0.1');
|
|
|
| # please add tests for complex numbers
|
| #
|
| # The closest I could find to documentation is here: http://tinyurl.com/27pj7c
|
| # I use 1i instead of i since I don't know if a bare i will be supported
|
|
|
| # log(exp(i pi)) = i pi log(exp(1)) = i pi
|
| #?pugs 2 todo 'feature'
|
| #?rakudo 2 skip 'parsefail'
|
| is_approx((log(-1 + 0i,), 0 + 1i * pi), "got the log of -1");
|
| is_approx((log10(-1 + 0i), 0 + 1i * pi), "got the log10 of -1");
|
|
|
| # log(exp(1+i pi)) = 1 + i pi
|
| #?pugs 2 todo 'feature'
|
| #?rakudo 2 skip 'parsefail'
|
| is_approx((log(-exp(1)) + 0i, 1 + 1i * pi), "got the log of -e");
|
| is_approx((log10(-10 + 0i), 1 + 1i * pi), "got the log10 of -10");
|
|
|
| #?pugs todo 'feature'
|
| #?rakudo 3 skip 'parsefail'
|
| is_approx((log((1+1i) / sqrt(2)), 1 + 1i * pi / 4), "got log of exp(i pi/4)");
|
| is_approx((log(1i), 1i * pi / 2), "got the log of i (complex unit)");
|
| #?pugs todo 'feature'
|
| is_approx((log(-1i), 1i * pi * 1.5), "got the log of -i (complex unit)");
|
|
|
| # TODO: please add more testcases for log10 of complex numbers
|
our Num multi method log10 (Num $x:) is export
A base 10 logarithm, othewise identical to log.
From t/spec/S29-num/rand.t lines 13–22 (4 √, 0 ×): (skip)
| # L<S29/Num/"=item rand"> |
| |
√ | ok(rand() >= 0, 'rand() returns numbers greater than or equal to 0'); |
√ | ok(rand() < 1, 'rand() returns numbers less than 1'); |
| |
| for 1 .. 10 { |
√ | ok rand(10) >= 0, "rand(10) always returns numbers greater than or equal to 0 ($_)"; |
√ | ok rand(10) < 10, "rand(10) always returns numbers less than 10 ($_)"; |
| } |
| |
our Num method rand ( Num $x: ) our Num term:<rand>
Pseudo random number in range 0 ..^ $x. That is, 0 is theoretically possible, while $x is not. The rand function is 0-ary and always produces a number from 0..^1. In any case, for picking a random integer you probably want to use something like (1..6).pick instead.
From t/spec/S29-num/sign.t lines 5–19 (6 √, 0 ×): (skip)
| # L<S29/Num/"=item sign"> |
| |
| =begin pod |
| |
| Basic tests for the sign() builtin |
| |
| =end pod |
| |
√ | is(sign(0), 0, 'got the right sign for 0'); |
√ | is(sign(-100), -1, 'got the right sign for -100'); |
√ | is(sign(100), 1, 'got the right sign for 100'); |
√ | is(sign(1.5), 1, 'got the right sign for 1.5'); |
√ | is(sign(-1.5), -1, 'got the right sign for -1.5'); |
| #?rakudo skip 'feature' |
√ | dies_ok { sign(undef) }, 'sign on undefined value fails'; |
our Int multi method sign ( Num $x: ) is export
Returns 1 when $x is greater than 0, -1 when it is less than 0, 0 when it is equal to 0, or undefined when the value passed is undefined.
From t/spec/S29-num/rand.t lines 23–44 (4 √, 0 ×): (skip)
| # L<S29/Num/"=item srand"> |
| |
| #?rakudo skip 'parsefail' |
√ | ok(srand(1), 'srand(1) parses'); |
| |
| #?rakudo skip 'parsefail' |
| { |
| sub repeat_rand ($seed) { |
| srand($seed); |
| for 1..99 { rand(); } |
| return rand(); |
| } |
| |
√ | ok(repeat_rand(314159) == repeat_rand(314159), |
| 'srand() provides repeatability for rand()'); |
| |
√ | ok(repeat_rand(0) == repeat_rand(0), |
| 'edge case: srand(0) provides repeatability'); |
| |
√ | ok(repeat_rand(0) != repeat_rand(1), |
| 'edge case: srand(0) not the same as srand(1)'); |
| } |
multi method srand ( Num $seed: ) multi srand ( Num $seed = default_seed_algorithm())
Seed the generator rand uses. $seed defaults to some combination of various platform dependent characteristics to yield a non-deterministic seed. Note that you get one srand() for free when you start a Perl program, so you must call srand() yourself if you wish to specify a deterministic seed (or if you wish to be differently nondeterministic).
From t/spec/S29-num/sqrt.t lines 5–31 (6 √, 1 ×): (skip)
| # L<S29/Num/"=item sqrt"> |
| |
| =begin pod |
| |
| Basic tests for the sqrt() builtin |
| |
| =end pod |
| |
√ | is_approx(sqrt(2), 1.4142135623730951, 'got the square root of 2'); |
√ | is_approx(sqrt(5), 2.23606797749979, 'got the square root of 5'); |
| #?rakudo 2 skip 'NaN not implemented' |
√ | ok(sqrt(-1), NaN, 'sqrt(-1) is NaN'); |
| |
| #WARNING: there is currently no spec which of the complex roots should be |
| #returned. We should change that. |
| #?rakudo skip 'parsefail' |
√ | is_approx(sqrt(-1 +0i), 1i, 'got the square root of -1+0i'); |
| |
| #?rakudo skip 'eval not implemented' |
| { |
| my $i = -1; |
× | is_approx(eval("sqrt($i.i)"), 1i, 'got the square root of -1.i'); |
| } |
| |
| #?rakudo 2 skip 'parsefail' |
√ | is_approx(sqrt(1i), (1+1i)/sqrt(2), 'got the square root of 1i'); |
√ | is_approx(sqrt(-1i), (1-1i)/sqrt(2), 'got the square root of -1i'); |
our Num multi method sqrt ( Num $x: ) is export
Returns the square root of the parameter.
From t/spec/S29-num/roots.t lines 5–40 (no results): (skip)
| # L<S29/Num/"=item roots">
|
|
|
| #?rakudo skip 'parsefail'
|
| {
|
| sub has_approx($n, @list) {
|
| for @list -> my $i {
|
| if approx($i, $n) {
|
| return 1;
|
| }
|
| }
|
| return undef;
|
| }
|
| }
|
|
|
| #?pugs todo 'feature'
|
| #?rakudo skip 'parsefail'
|
| {
|
| my @l = eval('roots(-1, 2)');
|
| ok(!$!, 'roots($x, $n) compiles');
|
| ok(@l.elems == 2, 'roots(-1, 2) returns 2 elements');
|
| ok(has_approx(1i, @l), 'roots(-1, 2) contains 1i');
|
| ok(has_approx(-1i, @l), 'roots(-1, 2) contains -1i');
|
| }
|
|
|
| #?pugs todo 'feature'
|
| #?rakudo skip 'parsefail'
|
| {
|
| my @l = eval('16.roots(4)');
|
| ok(!$!, '$x.roots($n) compiles');
|
| ok(@l.elems == 2, 'roots(16, 4) returns 4 elements');
|
| ok(has_approx(2, @l), 'roots(16, 4) contains 2');
|
| ok(has_approx(2i, @l), 'roots(16, 4) contains 2i');
|
| ok(has_approx(-2, @l), 'roots(16, 4) contains -2');
|
| ok(has_approx(-2i, @l), 'roots(16, 4) contains -2i');
|
| }
|
|
|
(in Num) method roots (Num $x: Int $n --> List of Num) is export
Returns a list of all $nth (complex) roots of $x
From t/spec/S29-num/complex.t lines 11–24 (no results): (skip)
| L<S29/Num/"=item cis"> |
| |
| =end pod |
| |
| #?rakudo skip "can't parse complex numbers" |
| { |
| |
| my $pi = 3.141592653589793238; |
| |
| is_approx((cis(0), 1 + 0i), "cis(0) == 1"); |
| is_approx((cis($pi), -1 + 0i), "cis(pi) == -1"); |
| is_approx((cis($pi / 2), 1i), "cis(pi/2) == i"); |
| is_approx((cis(3*$pi / 2),1i), "cis(3pi/2) == i"); |
| |
From t/spec/S29-num/complex.t lines 25–34 (no results): (skip)
| # L<S29/Num/"=item cis"> |
| # L<S29/Num/"=item unpolar"> |
| # |
| # Test that 1.unpor == cis |
| |
| for 1..20 -> $i { |
| my $angle = 2 * $pi * $i / 20; |
| is_approx((cis($i), 1.unpolar($i)), "cis(x) == 1.unpolar(x) No $i"); |
| } |
| |
our Complex multi method cis (Num $angle:) is export
Returns 1.unpolar($angle)
From t/spec/S29-num/complex.t lines 26–34 (no results): (skip)
| # L<S29/Num/"=item unpolar"> |
| # |
| # Test that 1.unpor == cis |
| |
| for 1..20 -> $i { |
| my $angle = 2 * $pi * $i / 20; |
| is_approx((cis($i), 1.unpolar($i)), "cis(x) == 1.unpolar(x) No $i"); |
| } |
| |
From t/spec/S29-num/complex.t lines 35–49 (no results): (skip)
| # L<S29/Num/"=item unpolar"> |
| # L<S29/Num/"=item abs"> |
| # |
| # Test that unpolar() doesn't change the absolute value |
| |
| my $counter = 1; |
| for 1..10 -> $abs { |
| for 1..10 -> $a { |
| my $angle = 2 * $pi * $i / 10; |
| is_approx((abs($abs.unpolar($angle)), $abs ), |
| "unpolar doesn't change the absolute value (No $counter)"); |
| $counter++; |
| } |
| } |
| |
From t/spec/S29-num/complex.t lines 50–60 (no results): (skip)
| # L<S29/Num/"=item unpolar"> |
| # |
| # Basic tests for unpolar() |
| |
| is_approx((4.unpolar(0), 4), "4.unpolar(0) == 4"); |
| is_approx((4.unpolar($pi/4), 2 + 2i),"4.unpolar(pi/4) == 2+2i"); |
| is_approx((4.unpolar($pi/2), 4i), "4.unpolar(pi/2) == 4i"); |
| is_approx((4.unpolar(3*$pi/4), -2 +2i),"4.unpolar(pi/4) == -2+2i"); |
| is_approx((4.unpolar($pi), -4), "4.unpolar(pi) == -4"); |
| } |
| #?rakudo emit skip_rest(); |
our Complex multi method unpolar (Num $mag: Num $angle) is export
Returns a complex number specified in polar coordinates. Angle is in radians.
our Seq multi method polar (Complex: $nim) is export
Returns (magnitude, angle) corresponding to the complex number. The magnitude is non-negative, and the angle in the range -π ..^ π.
From t/spec/S29-trig/trig.t lines 5–96 (no results): (skip)
| # L<S29/"The :Trig tag">
|
|
|
| =begin description
|
|
|
| Basic tests for trigonometric functions.
|
|
|
| =end description
|
|
|
| # See also: L<"http://theory.cs.iitm.ernet.in/~arvindn/pi/"> :)
|
| my $PI = 3.14159265358979323846264338327950288419716939937510;
|
|
|
| # -- pi
|
| is_approx((pi, $PI), "pi()");
|
| is_approx((pi + 3, $PI + 3), "'pi() + 3' may drop its parentheses before +3");
|
|
|
| # -- atan
|
| # The basic form of atan (one argument) returns a value in ]-pi, pi[.
|
| # Quadrants I, III
|
| is_approx((atan(1) / $PI * 180, 45));
|
| is_approx((atan(1/3*sqrt(3)) / $PI * 180, 30));
|
| is_approx((atan(sqrt(3)) / $PI * 180, 60));
|
|
|
| # Quadrants II, IV
|
| is_approx((atan(-1) / $PI * 180, -45));
|
| is_approx((atan(-1/3*sqrt(3)) / $PI * 180, -30));
|
| is_approx((atan(-sqrt(3)) / $PI * 180, -60));
|
|
|
| # S29: This second form of C<atan> computes the arctangent of $y/$x, and
|
| # **takes the quadrant into account**.
|
| # Quadrant I
|
| is_approx((atan(1, 1) / $PI * 180, 45));
|
| is_approx((atan(1, sqrt(3)) / $PI * 180, 30));
|
| is_approx((atan(1, 1/3*sqrt(3)) / $PI * 180, 60));
|
|
|
| # Quadrant II
|
| is_approx((atan(1, -1) / $PI * 180, 135));
|
| is_approx((atan(1, -1/3*sqrt(3)) / $PI * 180, 120));
|
| is_approx((atan(1, -sqrt(3)) / $PI * 180, 150));
|
|
|
| # Quadrant III
|
| is_approx((atan(-1, -1) / $PI * 180 + 360, 225));
|
| is_approx((atan(-1, -sqrt(3)) / $PI * 180 + 360, 210));
|
| is_approx((atan(-1, -1/3*sqrt(3)) / $PI * 180 + 360, 240));
|
|
|
| # Quadrant IV
|
| is_approx((atan(-1, 1) / $PI * 180 + 360, 315));
|
| is_approx((atan(-1, sqrt(3)) / $PI * 180 + 360, 330));
|
| is_approx((atan(-1, 1/3*sqrt(3)) / $PI * 180 + 360, 300));
|
|
|
| # -- sin, cos, tan
|
| # sin
|
| is_approx((sin(0/4*$PI), 0));
|
| is_approx((sin(1/4*$PI), 1/2*sqrt(2)));
|
| is_approx((sin(2/4*$PI), 1));
|
| is_approx((sin(3/4*$PI), 1/2*sqrt(2)));
|
| is_approx((sin(4/4*$PI), 0));
|
| is_approx((sin(5/4*$PI), -1/2*sqrt(2)));
|
| is_approx((sin(6/4*$PI), -1));
|
| is_approx((sin(7/4*$PI), -1/2*sqrt(2)));
|
| is_approx((sin(8/4*$PI), 0));
|
|
|
| # cos
|
| is_approx((cos(0/4*$PI), 1));
|
| is_approx((cos(1/4*$PI), 1/2*sqrt(2)));
|
| is_approx((cos(2/4*$PI), 0));
|
| is_approx((cos(3/4*$PI), -1/2*sqrt(2)));
|
| is_approx((cos(4/4*$PI), -1));
|
| is_approx((cos(5/4*$PI), -1/2*sqrt(2)));
|
| is_approx((cos(6/4*$PI), 0));
|
| is_approx((cos(7/4*$PI), 1/2*sqrt(2)));
|
| is_approx((cos(8/4*$PI), 1));
|
|
|
| # tan
|
| is_approx((tan(0/4*$PI), 0));
|
| is_approx((tan(1/4*$PI), 1));
|
| is_approx((tan(3/4*$PI), -1));
|
| is_approx((tan(4/4*$PI), 0));
|
| is_approx((tan(5/4*$PI), 1));
|
| is_approx((tan(7/4*$PI), -1));
|
| is_approx((tan(8/4*$PI), 0));
|
|
|
| # asin
|
| is_approx((try {asin(0)}, 0));
|
| #?pugs 2 todo 'feature'
|
| is_approx((try {asin(1/2*sqrt(2))}, 1/4*$PI));
|
| is_approx((try {asin(1)}, 2/4*$PI));
|
|
|
| # acos
|
| #?pugs 2 todo 'feature'
|
| is_approx((try {acos(0)}, 2/4*$PI));
|
| is_approx((try {acos(1/2*sqrt(2))}, 1/4*$PI));
|
| is_approx((try {acos(1)}, 0/4*$PI));
|
From t/spec/S29-trig/e.t lines 5–21 (no results): (skip)
| # L<S29/"The :Trig tag"> |
| |
| =begin description |
| |
| Basic tests for trigonometric functions. |
| |
| =end description |
| |
| # See also: L<"http://en.wikipedia.org/wiki/E_%28mathematical_constant%29"> :) |
| my $e = 2.71828182845904523536; |
| |
| is_approx(e , $e, "e, as a bareword"); |
| is_approx(e() , $e, "e(), as a sub"); |
| is_approx(1 + e(), $e+1, "1+e(), as a sub"); |
| is_approx(e() + 1, $e+1, "e()+1, as a sub"); |
| is_approx(1 + e, $e+1, "1+e, as a bareword"); |
| is_approx(e + 1, $e+1, "e+1, as a bareword"); |
The following are also defined in Num but not exported without a :Trig tag. (Which installs their names into Num::Trig, as it happens.)
Num multi method func ( Num $x: $base = 'radians' ) is export(:Trig)
where func is one of: sin, cos, tan, asin, acos, atan, sec, cosec, cotan, asec, acosec, acotan, sinh, cosh, tanh, asinh, acosh, atanh, sech, cosech, cotanh, asech, acosech, acotanh.
Performs the various trigonometric functions.
Option $base is used to declare how you measure your angles. Given the value of an arc representing a single full revolution.
$base Result ---- ------- /:i ^r/ Radians (2*pi) /:i ^d/ Degrees (360) /:i ^g/ Gradians (400) Num Units of 1 revolution.
Note that module currying can be used within a lexical scope to specify a consistent base so you don't have to supply it with every call:
my module Trig ::= Num::Trig.assuming(:base<degrees>);
This overrides the default of "radians".
our Num multi method atan2 ( Num $y: Num $y = 1 ) our Num multi atan2 ( Num $y, Num $x = 1 )
This second form of atan computes the arctangent of $y/$x, and takes the quadrant into account. Otherwise behaves as other trigonometric functions.
API document: Scalar
Scalar provides the basic tools for operating on undifferentiated scalar variables. All of the following are exported by default.
From t/spec/S29-scalar/defined.t lines 5–72 (21 √, 0 ×): (skip)
| # L<S29/Scalar/"=item defined"> |
| |
| =begin pod |
| |
| Tests for the defined() builtin |
| |
| =end pod |
| |
| |
| |
√ | ok(!defined(undef), 'undef is not defined'); |
| |
√ | ok(defined(1), 'numeric literal 1 is defined'); |
√ | ok(defined(""), 'empty string is defined'); |
√ | ok(defined("a"), '"a" is defined'); |
√ | ok(defined(0), 'numeric literal 0 is defined'); |
| |
| my $foo; |
√ | ok(!defined($foo), 'unassigned variable $foo is undefined'); |
| |
| $foo = 1; |
√ | ok(defined($foo), 'variable $foo is now defined (as numeric literal 1)'); |
| |
| $foo = ""; |
√ | ok(defined($foo), 'variable $foo is now defined (as a empty string)'); |
| |
| $foo = undef; |
√ | ok(!defined($foo), 'variable $foo is now undefined again'); |
| |
| $foo = "a"; |
√ | ok(defined($foo), 'variable $foo is now defined (as string "a")'); |
| |
| $foo = 0; |
√ | ok(defined($foo), 'variable $foo is now defined (as numeric literal 0)'); |
| |
| undefine($foo); |
√ | ok(!defined($foo), 'undef $foo works'); |
| |
| # try the invocant syntax |
| |
| my $foo; |
√ | ok(!$foo.defined, 'unassigned variable $foo is undefined'); |
| |
| $foo = 1; |
√ | ok($foo.defined, 'variable $foo is now defined (as numeric literal 1)'); |
| |
| $foo = ""; |
√ | ok($foo.defined, 'variable $foo is now defined (as a empty string)'); |
| |
| $foo = undef; |
√ | ok(!$foo.defined, 'variable $foo is now undefined again'); |
| |
| $foo = "a"; |
√ | ok($foo.defined, 'variable $foo is now defined (as string "a")'); |
| |
| $foo = 0; |
√ | ok($foo.defined, 'variable $foo is now defined (as numeric literal 0)'); |
| |
| undefine($foo); |
√ | ok(!$foo.defined, 'undef $foo works'); |
| |
| |
| # While porting a Perl 5 solution to QoTW regular #24, I noticed the following bug: |
| # my %a = (a => 1); |
| # defined %a{"b"}; # true! |
| my %a = (a => 1); |
√ | ok defined(%a{"a"}), "defined on a hash with parens (1)"; |
√ | ok !defined(%a{"b"}), "defined on a hash with parens (2)"; |
our Bool multi defined ( Any $thing ) our Bool multi defined ( Any $thing, ::role )
defined returns true if the parameter has a value and that value is not the undefined value (per undef), otherwise false is returned.
Same as Perl 5, only takes extra optional argument to ask if value is defined with respect to a particular role:
defined($x, SomeRole);
A value may be defined according to one role and undefined according to another. Without the extra argument, defaults to the definition of defined supplied by the type of the object.
From t/spec/S29-scalar/undef.t lines 57–203 (no results): (skip)
| # L<S29/Scalar/"=item undefine">
|
| {
|
| my @ary = "arg1";
|
| my $a = @ary.pop;
|
| ok(defined($a), "pop from array");
|
| $a = @ary.pop;
|
| ok(!defined($a), "pop from empty array");
|
|
|
| @ary = "arg1";
|
| $a = @ary.shift;
|
| ok(defined($a), "shift from array");
|
| $a = @ary.shift;
|
| ok(!defined($a), "shift from empty array");
|
|
|
| my %hash = ( bar => 'baz', quux => 'quuz' );
|
| ok(defined(%hash<bar>), "hash subscript");
|
| ok(!defined(%hash<bargho>), "non-existent hash subscript");
|
|
|
| undefine %hash<bar>;
|
| ok(!defined(%hash<bar>), "undefine hash subscript");
|
|
|
| %hash<bar> = "baz";
|
| %hash.delete("bar");
|
| ok(!defined(%hash<bar>), "delete hash subscript");
|
|
|
| ok(defined(@ary), "aggregate array defined");
|
| ok(defined(%hash), "aggregate hash defined");
|
|
|
| undefine(@ary);
|
| #?pugs todo 'bug'
|
| ok(!defined(@ary), "undefine array");
|
|
|
| undefine(%hash);
|
| #?pugs todo 'bug'
|
| ok(!defined(%hash), "undefine hash");
|
|
|
| @ary = (1);
|
| ok(defined(@ary), "define array again");
|
| %hash = (1,1);
|
| ok(defined(%hash), "define hash again");
|
| }
|
|
|
| {
|
|