@@ -428,11 +428,151 @@ say 42 ∈ +«<42 100 200>; # OUTPUT: «True»
428
428
429
429
Be mindful of these object identity differences and coerce your allomorphs as needed.
430
430
431
- = head1 Native
431
+ = head1 Native Numerics
432
432
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.
434
435
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
436
576
437
577
= head1 Numeric Infectiousness
438
578
0 commit comments