Skip to content

Commit 06ebcee

Browse files
committed
[CaR Grant] Document native types
1 parent fb060ee commit 06ebcee

File tree

1 file changed

+143
-3
lines changed

1 file changed

+143
-3
lines changed

doc/Language/numerics.pod6

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -428,11 +428,151 @@ say 42 ∈ +«<42 100 200>; # OUTPUT: «True␤»
428428
429429
Be mindful of these object identity differences and coerce your allomorphs as needed.
430430
431-
=head1 Native
431+
=head1 Native Numerics
432432
433-
=head2 C<int>, C<int8>, C<int16>, C<int32>, and C<int64>
433+
As the name suggests, native numerics offer access to native numerics—i.e. those offered directly
434+
by your hardware. This in turn offers two features: overflow/underflow and better performance.
434435
435-
=head2 C<num>, C<num32>, and C<int64>
436+
B<NOTE:> at the time of this writing (2018.05), certain implementations (such as Rakudo) offer
437+
somewhat spotty details on native types, such as whether C<int64> is available and is of 64-bit
438+
size on 32-bit machines, and how to detect when your program is running on such hardware.
439+
440+
=head2 Available Native Numerics
441+
442+
=begin table
443+
444+
Native type | Base numeric | Size
445+
============+==================+===============
446+
int | integer | 64-bits
447+
int8 | integer | 8-bits
448+
int16 | integer | 16-bits
449+
int32 | integer | 32-bits
450+
int64 | integer | 64-bits
451+
452+
uint | unsigned integer | 64-bits
453+
uint8 | unsigned integer | 8-bits
454+
uint16 | unsigned integer | 16-bits
455+
uint32 | unsigned integer | 32-bits
456+
uint64 | unsigned integer | 64-bits
457+
458+
num | floating point | 64-bits
459+
num32 | floating point | 32-bits
460+
num64 | floating point | 64-bits
461+
462+
=end table
463+
464+
=head2 Creating Native Numerics
465+
466+
To create a natively-typed variable or parameter, simply use the name of one of the available
467+
numerics as the type constraint:
468+
469+
=begin code
470+
my int32 $x = 42;
471+
sub foo(num $y) {}
472+
class { has int8 $.z }
473+
=end code
474+
475+
At times, you may wish to coerce some value to a native type without creating any usable variables.
476+
There are no C<.int> or similar coersion methods (method calls are latebound, so they're not
477+
well-suited for this purpose). Instead, simply use an anonymous variable:
478+
479+
=begin code :preamble<my $y; my $z;>
480+
some-native-taking-sub (my int $ = $y), (my int32 $ = $z)
481+
=end code
482+
483+
=head2 Overflow/Underflow
484+
485+
Trying to B<assign> a value that does not fit into a particular native type, produces an exception:
486+
487+
=begin code
488+
my int $x = 2¹⁰⁰;
489+
# OUTPUT:
490+
# Cannot unbox 101 bit wide bigint into native integer
491+
# in block <unit> at -e line 1
492+
=end code
493+
494+
However, modifying an already-existing value in such a way that it becomes too big/small, produces
495+
overflow/underflow behaviour:
496+
497+
=begin code
498+
my int $x = 2⁶³-1;
499+
say $x; # OUTPUT: «9223372036854775807␤»
500+
say ++$x; # OUTPUT: «-9223372036854775808␤»
501+
502+
my uint8 $x;
503+
say $x; # OUTPUT: «0␤»
504+
say $x -= 100; # OUTPUT: «156␤»
505+
=end code
506+
507+
Creating objects that utilize native types does not involve direct assignment by the programmer
508+
and so these contructs offer overflow/underflow behaviour instead of throwing exceptions. The
509+
same reasoning applies when a routine with a smaller native type is called with a larger value.
510+
511+
=begin code
512+
say Buf.new(1000, 2000, 3000).List; # OUTPUT: «(232 208 184)␤»
513+
say my uint8 @a = 1000, 2000, 3000; # OUTPUT: «232 208 184␤»
514+
515+
sub foo(int8 $x) { say $x }
516+
foo my int $x = 10000; # OUTPUT: «16␤»
517+
=end code
518+
519+
=head2 Auto-boxing and Multi Dispatch
520+
521+
While they can be referred to as "native I<types>", native numerics are not actually classes
522+
that have any sort of methods available. However, you I<can> call any of the methods available
523+
on non-native versions of these numerics. What's going on?
524+
525+
=begin code
526+
my int8 $x = -42;
527+
say $x.abs; # OUTPUT: «42␤»
528+
=end code
529+
530+
This behaviour is known as "auto-boxing". The compiler automatically "boxes" the native type
531+
into a full-featured higher-level type with all the methods. In other words, the C<int8> above
532+
was automatically converted to an L<Int> and it's the L<Int> class that then provided the L<abs>
533+
method that was called.
534+
535+
This detail becomes significant in two situations. First, if a routine is an C<only>—i.e. it is
536+
not a L«C<multi>|/language/functions#Multi-dispatch»—that takes a non-native type but a native
537+
one was given during the call, it will be autoboxed. However, no auto-boxing will occur
538+
with a L«C<multi>|/language/functions#Multi-dispatch» candidate—you must provide a native candidate
539+
for it to be callable.
540+
541+
=begin code
542+
sub one-over (Int $x) { 1/$x }
543+
one-over my int $ = 42; # OK; auto-boxed
544+
545+
multi one-over-multi (Int $x) { 1/$x }
546+
one-over-multi my int $ = 42; # BAD; no native candidate
547+
548+
multi one-over-multi2 (Int $x) { 1/$x }
549+
multi one-over-multi2 (int $x) { 1/$x }
550+
one-over-multi2 my int $ = 42; # OK; we have a native candidate
551+
=end code
552+
553+
The size of the native type does not play a role in dispatch and an C<int8> is considered to be
554+
the same as C<int16> or C<int>:
555+
556+
=begin code
557+
multi foo(int $x) { say "int" }
558+
multi foo(int32 $x) { say "int32" }
559+
foo my int $x = 42;
560+
# OUTPUT:
561+
# Ambiguous call to 'foo(Int)'; these signatures all match:
562+
# :(int $x)
563+
# :(int32 $x)
564+
=end code
565+
566+
A small exception to the multi dispatch rule involves constant-foldable routines that are called
567+
with a native type and another argument that's a numeric literal small enough to fit to a
568+
native type. This feature exists to support native (faster) versions of certain operators:
569+
570+
=begin code
571+
multi infix:<foo> (Int, Int) is pure { "full" }
572+
multi infix:<foo> (int, int) is pure { "native" }
573+
say 42 foo 42; # OUTPUT: «full␤»
574+
say 42 foo my int $ = 42; # OUTPUT: «native␤»
575+
=end code
436576
437577
=head1 Numeric Infectiousness
438578

0 commit comments

Comments
 (0)