use types;

YAPC::EU 2011

rurban - Reini Urban
vienna.pm => houston.pm

Goal



Provide type semantics to enable more compile-time optimizations, to make Perl and compiled Perl smaller and faster.

Outline

About me

About me

Architect. Mainly LISP for several years. Perl as better build system.

rurban maintains cygwin perl since 5.8.8 and some modules: illguts, B::* => 5.10, mainly the "compiler".

No perl dayjob, just for fun. Until now.

In the future a lot more time for the compiler and CORE. Left AVL (automotive industry), went to cPanel to improve the compiler.

Perl's Type System

my int $var# or our

# my :attribs are not known at compile-time, only our.
$ perl -c-e 'package int; package main; our int $i:const;'
    Invalid SCALAR attribute: const at -e line 1
$ perl -c-e 'package int; package main; my int $i:const;'
    -e syntax OK

FETCH_SCALAR_ATTRIBUTES => New CHECK_SCALAR_ATTRIBUTES callback for my.

Perl's Type System

Yes, the language already has one. CORE:

  my TYPE $var;
  sub name (proto) {} => proto: &name->pv

Only a few out-of-CORE implementations:

Moose, fields, types, typesafety, Lexical::Types, Attribute::Types (run-time)

Params: Devel::Declare, Params::Validate, Params::Classify
Objects: Class::Meta, Moose

Prototypes

No standard prototype language, no CPAN prototype parser!

# types 0.x
sub foo (int $foo) { my ($foo) = @_ } # return type implicit. 
#No optree injection as in Devel::Declare

# typesafety
sub foo (intintundef# returns int

# types 1.0
sub foo (int $i => int) { return 2 * $i } # return type explicit

Prototypes

No standard prototype language, no CPAN prototype parser!

# Devel::Declare, Method::Signatures
method hello (Str :$whoInt :$age where { $_ > 0 }) {
  $self->say("Hello ${who}, I am ${age} years old!");
}

# Moose
has 'accessor' => (isa => Int, is => 'rw', default => 1);

Perl's Type System

At first a look at CORE types, not the language:

SCALAR (non-strict, VB-like): IV, NV, UV, PV, ...

ARRAY (non-strict): AV

HASH (non-strict): HV

Objects ("stashes", @ISA, declaration)

Perl's Type System - SCALAR

SCALAR (non-strict, VB-like)

multiple types (IV,NV,PV) per variable, context dependent.

internally upgraded: IV => PVIV => PVNV

Perl's Type System - SCALAR

SCALAR (non-strict, VB-like)

multiple types (IV,NV,PV) per variable, context dependent.

IV: integer

Perl's Type System - SCALAR

SCALAR (non-strict, VB-like)

multiple types (IV,NV,PV) per variable, context dependent.

Typed IV: integer unblessed, untied. my int $i; ~SV_SMAGIC => SVf_FAKE: no head

=>

Perl's Type System - SCALAR

SCALAR (non-strict, VB-like)

multiple types (IV,NV,PV) per variable, context dependent.

internally upgraded: IV => NV

Perl's Type System - SCALAR

SCALAR (non-strict, VB-like)

multiple types (IV,NV,PV) per variable, context dependent.

internally upgraded: IV => NV => PVNV

Perl's Type System - SCALAR

SCALAR (non-strict, VB-like)

internally upgraded: IV => PVIV => PVNV => "Objects" => Tie

Perl's Type System - SCALAR

"STASH" - Hierarchical symbol table,
used as package name for Objects. i.e. "Class pointer"

Perl's Type System - ARRAY

ARRAY (non-strict)

Keys are integers, Values any SCALAR

Perl's Type System - ARRAY

ARRAY (non-strict)

Keys are integers, Values any SCALAR

@a = ("any"12.5006, \&code, ['arrayref'], {hashref=>1});

Perl's Type System - ARRAY

ARRAY (non-strict)

Keys are integers, Values any SCALAR - flexible, untyped, big

@a = ("any"12.5006, \&code, ['arrayref'], {hashref=>1});

Typed ARRAY

Typed ARRAYs (optional, faster, less space)

Keys are integers, Values of one type only (native)

  my int @a$#a=256;     # pre-allocate: 256 * sizeof(IV)
  my int @a = (1);           # non-fixed size: 3 * sizeof(IV)
  my int @a :const = (1); # fixed size: 1 * sizeof(IV)

Untyped:

  my @a$#a=256;         # pre-allocate: 256 * sizeof(SV)

Typed ARRAY

  my int @a;

AvTYPED && (IOK | NOK | POK)

Typed ARRAY

  my int @a;

Declaration already possible now!

  perl -we'package int; package main; my int @a;'
  -e syntax ok

int must be a package definition.

Note: @a is currently declared as int, but not blessed.

Perl's Type System - HASH

HASH untyped: flexible, but big

Keys any SCALAR, Values any SCALAR

  %h = ('any' => ["any"12.5006];
        1     => 1,
        1.005 => 2.5);

Internally: Keys are stringified.

Perl's Type System - HASH

HASH untyped: flexible
Keys any SCALAR, Values any SCALAR

Typed HASH

HASH typed: fast, small

Keys STRING only, Values typed

  my string %h$h{'x'} = 'string';
  my int %h;    $h{'x'} = 1;
  my double %h$h{'x'} = 1.0;

Typed HASH

HASH typed: directer access, small
Keys STRING only, Values typed

Typed HASH

HASH typed: fast, small

Keys STRING only, Values are typed.

  my int %h$h{'any'} = 1;
  
  $h{2} = 1;
    => Wrong type: hash key no string
  
  $h{'2'} = '1';
    => Wrong type: hash value no int 

Perfect HASH

Perfect hashes - guaranteed O(1) lookup, dynamic hash function generation, no collisions
Library cmph BDZ algorithm ("RAM hashing")

study untyped hash => copies the old perl hash (HV) to new perfect hash (PH).

Perfect HASH

Perfect hash. Should be typed to optimize implementation.

  my int %h :const = ('my' => 1'your' => 2);

:const hashes are always :perfect
No need to study with :const and init on declaration.

  my %h :const = ('my' => 1'your' => 2);
  # untyped: value = SV

Perfect HASH Idioms

- Avoid copy from perl hash to perfect hash.

  my int %h :perfect;
  $h{$_}=1 for @h;
  study %h;

Perfect HASH Idioms

- Declare size in advance.

  my int %h :perfect;
  length %h = length @h;         # not legal yet, but should be
  $h{$_}=1 for @h;
  study %h;

Perfect HASH Idioms

- :const hash with computed key => values, without study

Idea 1

  my int %h :const;
  length %h = length @keys;       # not legal yet, but should be
  $h{$_} = $i++ for @keys;

Init until length is filled

Perfect HASH Idioms

- :const hash with computed key => values, without study

Idea 2

  my int %h :const = map { $h{$_} => $i++}  @keys;
=>
  my int %h :const;
  { $h{$_} = $i++ for @keys; }

Initialization on next expression, usually a block.

Perl's Type System - OBJECTS

OBJECTS: typed, but dynamic

run-time changable, mostly no compile-time optimizations possible.

Features: STASH ("class hash"), @ISA (mro), DESTROY

Perl's Type System - OBJECTS

OBJECTS: typed, but dynamic.

Class by STASH, Inheritance by @ISA (mro), magic DESTROY and CLONE methods.

Four method calls possible:

Compilation of a function

Class::sub(ARGS...)

pushmark
ARGS...
gv => GV *Class::sub
entersub

Class->method()
$object->method()
Class->$method()
$object->$method()

Compilation of a static method call

Class::sub()

Class->method(ARGS...)

pushmark
const => PV "Class"
ARGS...
method_named => PV "method"
entersub

$object->method()
Class->$method()
$object->$method()

Compilation of a method call

$object->method(ARGS...)

pushmark
padsv => GV *object
ARGS...
method_named => PV "method"
entersub

Compilation of a method call

Class->$method(ARGS...)

pushmark
const => PV "Class"
ARGS...
method => GV *method
entersub

Compilation of a method call

$object->$method(ARGS...)

pushmark
padsv => GV *object
ARGS...
method => GV *method
entersub

Optimization of a static method call

Class->method()

pushmark
const => PV "Class"
ARGS...
method_named => PV "method"
entersub
=>
pushmark
const => PV "Class"
ARGS...
gv => GV *Class::method
entersub

Optimization of a static method call

Class->method(...) => &Class::method('Class', ...)

if defined &Class::method

or package Class :locked or in Moose immutable.
i.e. not changed at run-time.

=> 4% faster method calls.

Note: @Class::ISA :const = qw(bla); does not help.

Optimization of other method calls

Dynamic method calls are possible to optimize in a similar way, if the object is declared - known class at compile-time.

  my My::Class $object = My::Class->new;
  $object->call();

  my My::Class $object = My::ParentClass->new;
  bless $object'My::Class';
  $object->call();

Inherited methods are optimizable if all classes in path to the final class are :locked, resp. immutable.

Summary so far

All this is possible now, without changing the language.

Just optimized implementations are missing.

I heard that in July 2011 Moose methods of immutable classes are going to be inlined, but what I saw so far it's not using optree changes like these to speed it up.

More optimizations

More compile-time optimizations.

:const for variables

:locked for packages: const @ISA, no run-time created methods.

use types;

types is Artur Bergman's compile-time checking attempt from 2002, after the compiler, B::Generate and optimize.

And before optimizer, which uses types to improve the optree.

use types;

types does compile-time type-checking only.

compile-time type-optimizations in optimizer.

Problem: slower, not faster.

use types;

The idea is to make programs with use types;

faster, not slower.

And define basic scalar types from CORE

int, double and string

B::CC

The same types and declarations are used in B::CC also to optimize types even further.

B::CC - optimizing perl compiler

B::CC also needs a syntax to optionally declare simple types:

int and double (strict)

So far it was done by magic variable name suffices: $a_i, $n_d;

faster, much faster

B::CC - User Type declarations

Strict types as class, and optional type hints as attributes.

  my int $foo :const;

With use types you get type-declarations,
partial type-safety, and
type optimizations at compile-time.

SUMMARY

    my double $foo = "string"#compile-time error 
    sub foo (int $foo) { my ($foo) = @_ }; 
    foo("hi"); #compile-time Type mismatch error 
 
    my int $int
    sub foo { my double $fooreturn $foo } 
    $int = $foo# compile-time Type mismatch error 

    my int @array = (0..10); # optimized internal representation 
    $array[2] = 2;       # no SV, just the raw int at slot 2. 

SUMMARY

    my int @array :const = (0..10); 
      # even more optimized internal representation 
    $array[2] = 2# int @array is readonly 
    $array[2] = '2'# compile-time const error 

    my string %stash :perfect =  
      (foo => 'str1', bar => 'str2'); # perfect hash (stashes)
    ; # more init... 
    study %stash# initialization finished 

    print $stash{foo}; # faster lookup O(1) 
    $stash{new} = 1;   # compile-time Type mismatch error

SUMMARY

    my int $i :double;  # declares a IV with SVf_NOK.  
    my $i:int:double;   # same but without type-check 
    my int $i;          # declares an IV.  
    my $i:int;          # same but without type-check 

    my int $i :string;  # declares a PVIV. 
    my int @array :unsigned = (0..4);  
        # Will be used as c var in faster arithmetic and cmp. 
        # Will use no SV value slot, just the direct value. 
 
    my string %hash :const = (foo => 'any', bar => 'any');  
        # declare string keys only 
        # generate as read-only perfect hash. 

Questions?

Questions?

http://blogs.perl.org/users/rurban/2011/02/use-types.html