Importing a type declared with Type::Library in the same file but a different package?

122 views Asked by At

Why doesn't the following code, ripped directly from the docs, work?

package Types::Mine {
   use Scalar::Util qw(looks_like_number);
   use Type::Library -base;
   use Type::Tiny;

   my $NUM = "Type::Tiny"->new(
      name       => "Number",
      constraint => sub { looks_like_number($_) },
      message    => sub { "$_ ain't a number" },
   );

   __PACKAGE__->meta->add_type($NUM);

   __PACKAGE__->meta->make_immutable;
}

When I try to ->import it from the same file.

package main {
  use v5.30;
  BEGIN { Types::Mine->import( qw(Number) ) };
  die Number;
}

I'm getting,

Could not find sub 'Number' exported by Types::Mine at /tmp/test.pl line 20.
BEGIN failed--compilation aborted at /tmp/test.pl line 20.

Shouldn't you be able to import a type library declared in the same file, though a different package, with

BEGIN { Types::Mine->import( qw(Number) ) };
1

There are 1 answers

1
Evan Carroll On

You have to either

  1. Wrap the package in BEGIN {}, because remember if you're trying to write use in one package, the require and the import is in the BEGIN {} block too, ie these two are the same

    use Foo;
    BEGIN { require Foo; Foo->import() }
    

    So you'll want to wrap the entire package in the BEGIN {} block, AND the import statement,

    BEGIN {
        package Types::Mine {
           use Scalar::Util qw(looks_like_number);
           use Type::Library -base;
           use Type::Tiny;
    
           my $NUM = "Type::Tiny"->new(
              name       => "Number",
              constraint => sub { looks_like_number($_) },
              message    => sub { "$_ ain't a number" },
           );
    
           __PACKAGE__->meta->add_type($NUM);
    
           __PACKAGE__->meta->make_immutable;
        }
    }
    
  2. Cheat, and put nothing in BEGIN, but predeclare the sub.

    use v5.30;
    use sub Number;
    Types::Mine->import( qw(Number) );
    die Number;
    

    Note this method generates a warning for "Overwriting existing sub" in Exporter::Tiny, which can be silenced by instead doing,

    BEGIN { Types::Mine->import( { replace => 1 }, qw(Number) ) }
    

First option provided by ilmari.