Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Type system

Reini Urban edited this page Jan 7, 2016 · 27 revisions

See the perltypes documentation from master, and the latest version is usually in the feature/gh7-signatures or featurex/gh16-multi branch.

In the featurex/gh7-sigs+libs branch several libraries are already "modernized", i.e. converted to typed signatures.

See for example the modernization of Test-Simple in commit 2d39610cb5.

The translation is pretty straightforward:

-sub is_eq {
-    my( $self, $got, $expect, $name ) = @_;
+sub is_eq ( $self, $got?, $expect?, $name?) {

The ? suffix from perl6 denotes an optional argument. If left out in the call, the value will be undef. There's no arity inspection as in @_.

$self is still in the signature. When is_eq is declared as method and not as sub, $self is not needed anymore and should be omitted. This is currently in work in the feature/gh16-multi branch.

To type or not?

-sub skip {
-    my( $self, $why, $name ) = @_;
-    $why ||= '';
-    $name = '' unless defined $name;
+sub skip ( $self, str $why='', $name? ) {
     $self->_unoverload_str( \$why );

$why is declared with the str coretype. str is the unboxed variant of the perl5-level boxed Str type, same as in Perl6. That means the compiler accepts only strings, not other scalars, and only strings which are known to the compiler at compile-time. Those strings will then be optimized to fast unboxed variants if possible or not, as the compiler sees fit.

A call to skip needs to stringify the $why argument, otherwise you get a compile-time error.

skip($test->{why}, "not working yet"); will be invalid. 
skip("$test->{why}", "not working yet"); is invalid. 

$name? should have also been declared as str $name=undef instead. This is currently valid code I think, but inconsistent with the current type system. undef is no str type. It really should be str? $name?, str? denoting str or the Undef type.

int vs Int vs Numeric

The type int cannot overflow to a float, a number. This is just as under use integer. Arithmetic ops with int are much faster than with generic numbers of type Numeric. E.g. the generic add op is 50 lines of c code, which calculates the sum twice and checks both args for UV, IV or NV, and the for possible overflow. The optimized Int variant for add where both arguments are int is one line, and 10x faster.

The optimized int variant where both arguments are unboxed, true native ints, is 20x faster, as the value needs not be extracted from the SV head, the result needs not be changed to an SvIV, it is just a single word.

But with the declared int type you cannot just pass normal expressions to this method anymore. E.g. with the skip similar to above, just as Test::More function and declared as

cpan/Test-Simple/lib/Test/More.pm
-sub skip {
-    my( $why, $how_many ) = @_;
+sub skip ( str $why, Int $how_many = 0) {
     my $tb = Test::More->builder;

-    unless( defined $how_many ) {
+    unless ($how_many) {

We need the numeric argument $how_many, which is often mixed up with str $why. We can declare $how_many as int, Int or Numeric, but overflow to NV (the Num type as in perl6) makes no sense as $how_many is later used as loop counter.

So we have to fix several wrong type usages of this skip, as seen below.

-- cpan/Test-Harness/t/source_handler.t
+++ cpan/Test-Harness/t/source_handler.t
@@ -355,9 +355,9 @@ sub test_handler {

     SKIP:
     {
-            my $planned = 1;
+            my int $planned = 1;
             $planned += 1 + scalar @{ $test->{output} } if $test->{output};
-            skip $test->{skip_reason}, $planned if $test->{skip};
+            skip "$test->{skip_reason}", $planned if $test->{skip};

We need to stringify the $why argument, and type the $planned number to int to bypass the type checker.

Clone this wiki locally