What is the simplest way to check if invalid arguments are passed to the constructor method new
?
use v6;
unit class Abc;
has Int $.a;
my $new = Abc.new( :b(4) );
The ClassX::StrictConstructor
module should help. Install it with zef install ClassX::StrictConstructor
and use it like so:
use ClassX::StrictConstructor;
class Stricter does ClassX::StrictConstructor {
has $.thing;
}
throws-like { Stricter.new(thing => 1, bad => 99) }, X::UnknownAttribute;
TLDR; If you are just worried about someone accidently mis-typing :a(4)
as
:b(4)
, it might be better to just mark $.a
as required.
class ABC {
has Int $.a is required;
}
ABC.new( :b(4) ); # error
# The attribute '$!a' is required, but you did not provide a value for it.
A quick hack would be to add a submethod TWEAK
that makes sure any named values that you don't specify aren't there. It doesn't interfere with the normal workings of new
and BUILD
, so the normal type checks work without having to re-implement them.
class ABC {
has Int $.a;
submethod TWEAK (
:a($), # capture :a so the next won't capture it
*% # capture remaining named
() # make sure it is empty
) {}
}
A slightly more involved (but still hacky) way that should continue to work for subclasses, and that doesn't need to be updated with the addition of more attributes:
class ABC {
has Int $.a;
submethod TWEAK (
*%_ # capture all named
) {
# get the attributes that are known about
# (should remove any private attributes from this list)
my \accepted = say self.^attributes».name».subst(/.'!'/,'');
# ignore any that we know about
%_{|accepted}:delete;
# fail if there are any left
fail "invalid attributes %_.keys.List()" if %_
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With