use Carp; my %FOO_KNOWN_ARGS = map {$_=>1} qw/ quz baz /; sub foo { my %args = @_; $FOO_KNOWN_ARGS{$_} or croak "Invalid argument '$_'" for keys %args; # ... } foo(quz=>1,baz=>1); foo(quz=>1,baz=>1,bar=>1); # dies #### use Hash::Util qw/lock_ref_keys/; my $foo = {}; lock_ref_keys($foo, qw/ quz baz /); $foo->{quz} = 1; $foo->{bar} = 1; # dies #### { package Foo; use Moo; use Types::Standard qw/ Str Int /; use Type::Utils qw/ declare as where /; use namespace::clean; has foo => ( is=>'ro', required=>1, isa => sub { $_[0]=~/^bar\d+$/ or die "Invalid foo" } ); has bar => ( is=>'ro', required=>1, isa => Int ); my $Hostname = declare as Str, where { /^\w+(\.\w+)*$/ }; has quz => ( is=>'ro', required=>1, isa => $Hostname ); sub baz { my $self = shift; print "baz, my foo is ",$self->foo,"\n"; } } my $foo = Foo->new(foo=>'bar123', bar=>4, quz=>'aa.bb.cc'); $foo->baz; baz2($foo); baz2({x=>1}); # dies # possible alternative to Foo::baz use Scalar::Util qw/blessed/; sub baz2 { my $foo = shift; die "Not a Foo" unless blessed($foo) && $foo->isa('Foo'); print "baz2, the foo is ",$foo->foo,"\n"; }