tobyink / p5-zydeco

Perl 5 distribution Zydeco; see homepage for downloads and documentation.
https://zydeco.toby.ink/
14 stars 3 forks source link

Types pre-declaration using declare keyword not possible with Type::Tiny v2 #15

Open smonff opened 1 year ago

smonff commented 1 year ago

Zydeco's declare keyword cannot be used with v2 of Type::Tiny anymore, for pre-declaration of types allowing to use them as barewords:

package Test::Keyword::Declare {

  use Zydeco declare => ['Person']; # Pre-declaration

  class Person {
    has age ( type => Int );
  }

  class Family {
    has members ( type => ArrayRef[Person] ); # :(
  }
}

perl -c test_keyword_declare.pl would throw the following message:

Expected Test::Keyword::Declare::Types to be a type library, but it doesn't seem to be at /home/smonff/project/declare/local/lib/perl5/Zydeco.pm line 1621.
BEGIN failed--compilation aborted at test_keyword_declare.pm line 12.

The error seems to be thrown by Type::Tiny::_DeclaredType. I realized it after deploying a new version of the Art::World module without upgrading libraries locally, but tests failed on CPAN Testers with Type::Tiny v2.

If we quote the type, not using the pre-declaration feature, the module compile normally:

package Test::Keyword::Declare {

  use Zydeco; # No pre-declaration

  class Person {
    has age ( type => Int );
  }

  class Family {
    has members ( type => 'ArrayRef[Person]' ); # This is ok
  }
}
perl -c test_keyword_declare.pm
test_keyword_declare.pm syntax OK
smonff commented 1 year ago

Remembering this similar issue from 2020 on RT.

tobyink commented 1 year ago

Yeah, I've encountered a similar error myself and been meaning to fix it.

A workaround for now is to do this somewhere near the top of your code:

BEGIN {
  package Test::Keyword::Declare::Types;
  use Type::Library -base;
};
smonff commented 1 year ago

Thanks.

vendethiel commented 7 months ago

Another question I have, which is probably just me being bad.

I have two files, a Game.pm file that has a character class. The gist of it is:

use Zydeco declare => [qw(Character)];
BEGIN { # https://github.com/tobyink/p5-zydeco/issues/15
  package Game::Types;
  use Type::Library -base;
}

class Character { ... }

Then, a Data.pm file that consumes it:

use Game; # I tried this but it didn't change anything: qw/:types/;
use Zydeco;

BEGIN { # https://github.com/tobyink/p5-zydeco/issues/15
  package Data::Types;
  use Type::Library -base, -extends => [ 'Game::Types' ]; # !!! THIS IS NECESSARY
}

class Updater {
  has characters ( is => ro, type => ArrayRef[Game::Character] );
  method with_char(Character $char) = ...;
}

The use Game; at the top of the file is enough to type my fields has (type => Game::Character); but requires the prefix, on the other hand, to use multiple dispatch based on type, I need to use Character in my Updater::Method. I can't interchangeably use Character or Game::Character, and to use Character in my method, I need my type library to extend Game::Types... But I don't need that to type my field.

I'm a bit at a loss for explanations right now, it's probably something to do with the way Zydeco is built but I'm not good enough with Perl to understand.

I did realize however, that fields did not go through MooX::Press's _build_method_signature_check, which calls 'Type::Registry'->for_class(...);, which explodes. It might be done at a different time than typechecking the fields?

Anyway, thanks for the great library :).