use strict; use warnings; # thanks.pm is a shim for declaring multiple packages in the same file. # It's on CPAN if you want it. Otherwise, just split them into separate # files. no thanks qw( MyApp::Types MyApp::Printer MyApp::Printer::ThreeColour MyApp::Printer::FourColour ); BEGIN { package MyApp::Types; use Type::Library -base, -declare => qw( ThreeColour FourColour ); use Type::Utils; use Types::Standard -types; use Types::ReadOnly -types; declare ThreeColour, as Locked[ Dict[ cyan => Optional[Num], magenta => Optional[Num], yellow => Optional[Num], ] ], coercion => 1; # black is referred to as "key" in CYMK printing. presumably because # using a name that abbreviated to "B" would be confused with "blue". declare FourColour, as Locked[ Dict[ @{ ThreeColour->parent->wrapped->parameters }, # voodoo? key => Optional[Num], ] ], coercion => 1; }; BEGIN { package MyApp::Printer; use Moose::Role; # Let's assume the printer is only capable of printing one pixel. has pixel => (is => 'ro'); sub dump { require Data::Dumper; Data::Dumper::Dumper(@_); } }; BEGIN { package MyApp::Printer::ThreeColour; use MyApp::Types -types; use Moose; with qw(MyApp::Printer); has '+pixel' => (isa => ThreeColour, coerce => 1); }; BEGIN { package MyApp::Printer::FourColour; use MyApp::Types -types; use Moose; with qw(MyApp::Printer); has '+pixel' => (isa => FourColour, coerce => 1); }; my $printer = 'MyApp::Printer::FourColour'->new( pixel => { cyan => 9.4, magenta => 7, yellow => 4 }, ); print($printer->dump); $printer->pixel->{key} = 9; # ok print($printer->dump); $printer->pixel->{black} = 6; # dies