Telephone +44(0)1524 64544
Email: info@shadowcat.co.uk

lpw-2012 - you-did-what

Sat Dec 22 00:30:00 2012

Slides for the talk you-did-what at lpw-2012

-

You
did
WHAT?

-

  $obj->foo;

-

What's
going
on?

-

Get the
class name
for $obj

-

Lookup 'foo'
via the MRO

-

MRO?

-

Method
resolution
order

-

mro.pm

-

mro::get_linear_isa

-

DFS
C3

-

  $obj->SUPER::foo

-

is actually

-

  $obj->Class::Of::Obj::SUPER::foo

-

Class::Of::Obj::SUPER

-

Reference to
SuperClass::Of::Obj

-

(well, it's
almost that)

-

Wait.

-

SuperClass::Of::Obj::foo

-

Fully
qualified
dispatch

-

  $obj->next::method

-

Always
dispatches
C3

-

So that
is ...

-

  package next;
  sub method {}

-

Oooo.

-

curry.pm

-

How many
times have
you written

-

  sub {
    $obj->foo(@_)
  }

-

  sub {
    $obj->foo(@args, @_)
  }

-

Well ...

-

  package curry;
  sub AUTOLOAD {
    (my $meth = $AUTOLOAD) =~ s/.*:://;
    my ($obj, @args) = @_;
    sub { $obj->$meth(@args, @_) }
  }

-

  my $cb = $obj->curry::foo;

-

  my $cb = $obj->curry::foo(@args);

-

(also provides
curry::weak::foo)

-

Also ...

-

  $obj->$foo

-

What?

-

$foo can be
a method name
or a coderef

-

So ...

-

How many
times have
you written

-

  if (
    blessed($obj)
    and $obj->can('foo')) {

-

Safe::Isa

-

  our $_can = sub {
    return unless blessed($_[0]);
    $_[0]->can($_[1]);
  }

-

  our @EXPORT = qw($_can);

-

  use Safe::Isa;
  ...
  if ($obj->$_can('foo')) {
    ...

-

(also provides
$_isa $_does
$_call_if_object)

-

  $obj->$foo

-

  $obj->${\foo()}

-

Huh?

-

foo() can
return a name
or a coderef

-

The ${}
derefs

-

  $obj->${\sub {
    my ($self, ...) = @_;
    ...
  }}

-

Inline
method
calls!

-

So, ok, what's
that going
to help with?

-

Importing ...

-

  sub import {
    ...
    require Foo;
    Foo->import;
  }

-

WRONG

-

import() methods
almost always
use caller()

-

  sub import {
    ...
    require Foo;
    goto &Foo::import;
  }

-

What if
you've got
two things
to import?

-

  sub import {
    ...
    require Foo;
    Foo->export_to_level(1);
  }

-

Only works
for Exporter
using things

-

Worse
still

-

pragmas!

-

strict
warnings
etc.

-

Affect
compilation
scope

-

  sub import {
    ...
    strict->import;

-

Damn

-

Anything that
works for
both?

-

  sub import {
    ...
    my $caller = caller;
    eval qq{
      package ${caller};
      Foo->import;
    }
  }

-

caller
correct
for
exporters

-

compilation
scope
right for
pragmas

-

  sub import {
    ...
    my $caller = caller;
    eval qq{
      package ${caller};
      Foo->import;
    }
  }

-

UGLY

-

Sufficiently
encapsulated
ugly is
indistinguishable
from beautiful

-

  my $importer = eval qq{
    package $target;
    sub {
      my \$m = splice \@_, 1, 1;
      shift->\$m(\@_)
    }
  };

-

  $importer->(import => @args);

-

So ...

-

  sub _importer {
    my $target = shift;
    \($importers{$target} ||= eval qq{
      package $target;
      sub {
        my \$m = splice \@_, 1, 1;
        shift->\$m(\@_)
      };
    } or die "Couldn't build importer for $target: $@")
  }

-

  sub import::into {
    my ($class, $target, @args) = @_;
    $class->${_importer($target)}(
      import => @args
    );
  }

-

Import::Into

-

  use Import::Into;

  sub import {
    my $target = caller;
    ...
    Thing1->import::into($target);
    Thing2->import::into($target, @args);
  }

-

Works for
modules

-

Works for
pragmas

-

(also provides
unimport::out_of)

-

I did
what?

-

Import::Into
Safe::Isa
curry

-

Import::Into
Safe::Isa
curry
(all already
on CPAN)

-

Hopefully
they'll be
useful

-

Sufficiently
encapsulated
insanity ...

-

Thank You
IRC:mst
mst@shadowcat.co.uk
@shadowcat_mst