Skip Menu |

This queue is for tickets about the Type-Tiny CPAN distribution.

Report information
The Basics
Id: 124728
Status: resolved
Priority: 0/
Queue: Type-Tiny

People
Owner: Nobody in particular
Requestors: djerius [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Type::Library::_mksub generates a new sub when importing types from another library
My apologies if the subject line is a bit unclear. The fundamental issue I'm running into is that the "factory" sub made available by a type library is regenerated by any libraries that inherit from it. Here's more background on what I'm trying to accomplish. I'm cleaning up several nested type libraries and would like to deprecate some of the types. I'd like for the deprecated types to issue a warning when the (for better name) "factory" sub which returns the type is run (rather than each time type verification is performed), so I thought that wrapping the "factory" sub created by Type::Library::_mksub would be the least intrusive method of doing so: package Type::Library::Role::Deprecate; use Scalar::Util (); use Role::Tiny; around '_mksub' => sub { my $orig = shift; my ( $class, $type ) = @_; my $sub = $orig->( @_ ); return $sub unless $class->meta->{deprecated}{ $type->qualified_name }; return sub { warn( $type->qualified_name . " is deprecated\n" ); &$sub; } }; sub deprecate { my $meta = shift->meta; my $class = Scalar::Util::blessed( $meta ); $meta->{deprecated}{"$class\::$_"} = 1 for @_; } 1; In my base type library: use Type::Library -base, -declare => qw( ChanType ChanSpec EnUnit EnSpec ); use Role::Tiny::With; with 'Type::Library::Role::Deprecate'; __PACKAGE__->deprecate( qw[ ChanType ChanSpec EnUnit EnSpec ] ); However, when another library extends mine (e.g. via Type::Utils::extends), Type::Library::add_type calls Type::Library::_mksub, which regenerates the "factory" sub using an unwrapped _mksub, and the deprecation notice isn't added. I'm ignorant of the reasons for not caching _mksub's results. It would make things like the above possible. Or, perhaps I'm going about this the wrong way. Thanks in advance. Diab
I haven't tried this, but have you tried wrapping _exporter_install_sub which Type::Library should inherit from Exporter::Tiny? It will get called like: Your::Library::Name->_exporter_install_sub($typename, $options, $global_options, $coderef) So you should be able to issue a warning when you detect that a deprecated type is being exported.
On Tue Apr 17 14:48:23 2018, TOBYINK wrote: Show quoted text
> I haven't tried this, but have you tried wrapping > _exporter_install_sub which Type::Library should inherit from > Exporter::Tiny? > > It will get called like: > > Your::Library::Name->_exporter_install_sub($typename, $options, > $global_options, $coderef) > > So you should be able to issue a warning when you detect that a > deprecated type is being exported.
I'm not sure how that would work. The way I understand the code, in the following scenario: package LibraryB; use Type::Library -base; use Type::Utils -all; BEGIN { extends LibraryA } 'extends' copies the types directly from LibraryA and adds them to LibraryB, bypassing an import, and thus LibraryA->_exporter_install_sub; LibraryB->_exporter_install_sub is invoked when someone imports LibraryB, but by then it's too late. I don't control LibraryB, just LibraryA, so can't wrap it in LibraryB. Even if I could, the warning would be elicited upon import of LibraryB, even via use LibraryB -types; so code which never uses the deprecated types would issue a warning. The following illustrates my understanding of how things work: # LibraryA.pm package LibraryA; use 5.10.0; use strict; use warnings; use Type::Library -base, -declare => 'Foo' ; use Types::Standard -types; use Type::Utils -all; sub _exporter_install_sub { my $class = shift; say $class, ": $_[0]"; $class->SUPER::_exporter_install_sub( @_ ); } declare Foo, as Str; 1; # LibraryB.pm package LibraryB; use 5.10.0; use strict; use warnings; use Type::Library -base; use Type::Utils -all; sub _exporter_install_sub { my $class = shift; say $class, ": $_[0]"; $class->SUPER::_exporter_install_sub( @_ ); } BEGIN { extends 'LibraryA' } 1; # typelib.pl use strict; use warnings; use LibraryB -types; And the output: % perl typelib.pl LibraryB: Foo
On Tue Apr 17 14:48:23 2018, TOBYINK wrote: Show quoted text
> I haven't tried this, but have you tried wrapping > _exporter_install_sub which Type::Library should inherit from > Exporter::Tiny? > > It will get called like: > > Your::Library::Name->_exporter_install_sub($typename, $options, > $global_options, $coderef) > > So you should be able to issue a warning when you detect that a > deprecated type is being exported.
Type::Tiny::Wrapper looks promising; I could create a Deprecated coercion which consisted simply of a warning issued by the precheck sub. Doesn't seem to pass its tests these days, though :(.
On Mon Apr 23 14:17:50 2018, DJERIUS wrote: Show quoted text
> On Tue Apr 17 14:48:23 2018, TOBYINK wrote:
> > I haven't tried this, but have you tried wrapping > > _exporter_install_sub which Type::Library should inherit from > > Exporter::Tiny? > > > > It will get called like: > > > > Your::Library::Name->_exporter_install_sub($typename, $options, > > $global_options, $coderef) > > > > So you should be able to issue a warning when you detect that a > > deprecated type is being exported.
> > Type::Tiny::Wrapper looks promising; I could create a Deprecated > coercion which consisted simply of a warning issued by the precheck > sub. Doesn't seem to pass its tests these days, though :(.
Here's my current solution after a forced install of Type::Tiny::Wrapper. package MyLibrary; [...] use Devel::Deprecate 'deprecate'; use Type::Tiny::Wrapper; my $Deprecated = Type::Tiny::Wrapper->new( pre_check => sub { deprecate( reason => "See docs for @{[ __PACKAGE__ ]}" ); } ); sub Deprecated($) { $Deprecated->wrap( @{ $_[0] } ) } declare PDLObj, as Deprecated [ InstanceOf ['PDL'] ]; It only issues a warning when a type is checked, rather than when the factory routine is called, so unfortunately this is in essence a runtime rather than a compile time check.
I wonder if adding a "deprecated => 1" option when creating a new type constraint might be the best option. A deprecated type could issue a warning when it's imported or when it's used, whichever occurs first.
Okay, so added $type->deprecated attribute. https://github.com/tobyink/p5-type-tiny/commit/c90861e8201d9e8354ed8d2e398b9add5fb611be A warning will be issued if you try to import a deprecated type. If you inherit from a deprecated type, your type will also be deprecated unless you explicitly pass `deprecated=>0` to the constructor.
On Sun Jul 01 10:47:15 2018, TOBYINK wrote: Show quoted text
> Okay, so added $type->deprecated attribute. > > https://github.com/tobyink/p5-type- > tiny/commit/c90861e8201d9e8354ed8d2e398b9add5fb611be > > A warning will be issued if you try to import a deprecated type. > > If you inherit from a deprecated type, your type will also be > deprecated unless you explicitly pass `deprecated=>0` to the > constructor.
Excellent! Thanks very much.
Subject: Allow types to be marked as deprecated
Fixed in 1.004000.
On Fri Jul 27 09:46:11 2018, TOBYINK wrote: Show quoted text
> Fixed in 1.004000.
Thanks!