Perl has always been pretty fuzzy with types, allowing you to convert things between numeric and string values transparently and automatically. Usually, Perl does the right thing, except when it doesn't. If you've ever messed about with Perl 5 internals, you know that there are actually several numeric types hiding behind the Perl programmer's concept of a scalar. Perl 6 works largely the same way with regard to automatic type conversion, but adds some optional type constraint checking and more robust numeric types.
At the heart of Perl 6's numeric type system is the
Numeric role. (Roles are an amazing way to do OO programming without the deficiencies of class hierarchies, and will be covered in a later post.)
Numeric is consumed (directly or indirectly) by the following builtin type classes:
- Num - floating point number
- Int - arbitrary-precision integer
- Rat - limited-precision rational number
- FatRat - arbitrary-precision rational number
- Complex - complex number
Let's write a program to see what types are returned by various literal expressions.
#!/usr/bin/env perl6 #file: ex3.pl6 say 3.WHAT; say 3.14159.WHAT; say 3.14159e0.WHAT; say (22/7).WHAT; say (3 + 4i).WHAT;
If we run that, we get:
perl6 ex3.pl6 (Int) (Rat) (Num) (Rat) (Complex)
There are immediately some interesting things to note. First is that the literal expression
3.14159 returns a rational number, as opposed to the floating point number one might expect from experience with most other programming languages. Perl 6 wants you to work with rationals in most cases, as this will generally get you the answers you actually want. To get a true float, you have to specify the literal in scientific notation (also called E-notation) with a base and power of 10 separated by an
As we might expect, a literal integer returns an
Int. Conveniently, a division expression of two integers also gets us a
Rat, which makes working with vulgar fractions extremely easy in Perl 6.
Finally, and perhaps most astoundingly, is Perl 6's builtin support for complex numbers, specified by simply including the symbol
i in the expression. Most programming languages, even fully dynamic ones, require loading special symbolic computation libraries to get complex number support, but with Perl 6, it's built right in. It has always surprised me that more languages didn't have native complex number support, since they're not especially hard. A complex number is just a pair of real numbers with special rules for arithmetic.
Speaking of that, let's see what the
Complex type can do.
#!/usr/bin/env perl6 #file: ex4.pl6 my Real $re = 4; my Real $im = 5; my Complex $c = $re + $im * i; say "our complex number is $c"; $c += 2 + 11i; say "plus 2 + 11i is $c"; say "the real part is " ~ $c.re ~ " and the imaginary part is " ~ $c.im;
perl6 ex4.pl6 our complex number is 4+5i plus 2 + 11i is 6+16i the real part is 6 and the imaginary part is 16
Rational numbers can also be interrogated about their numerators and denominators, and they add and subtract according to the rules of rational numbers, rather than of floats. Let's give it a try.
#!/usr/bin/env perl6 #file ex5.pl6 my Rat $foo = 31/17; say "numerator is " ~ $foo.numerator; say "denominator is " ~ $foo.denominator; $foo *= 9/13; say "foo is now " ~ $foo.numerator ~ '/' ~ $foo.denominator;
perl6 ex5.pl6 numerator is 31 denominator is 17 foo is now 279/221
Working with native rationals is obviously not as efficient as floats, which are hardware-optimized. But in modern environments, you won't notice it unless you're doing serious number-crunching. As always, Perl gives you enough control to be as general or specific as you want, with a sensible default to work with.