Perhaps the contructor could be modified. The current hashref would fall under a key named "params" and a different key named "groups" would list group validations. Then, as soon as an accessor is called, the "group" validations would be checked. This would eliminate the order dependence. Workable?
This still leaves it up to the person constructing the Params object ot specify what the overall validation function is ... maybe the %params hash is some global that gets re-used by all of the clients -- because if they don't then the method they are passing the Params too will fail when it tries to access things with a certian name -- but they can allways just choose to not pass a "groups" test and circumvent the tests.
I would recommend approaching this problem form a different direction -- seperate the "definition" of what a valid Param object is for a given context, from the "instantiation" of a particular instance.
Consider something like this...
#### in the library code ###
Sub::Param::make_new_param_type($param_type_name
\%param_definitions,
\&validity_function);
...
sub some_method {
my $param = shift;
die "die" unless $param->isValid($param_type_name);
...
}
sub some_other_method {
my $param = shift;
die "die" unless $param->isValid($param_type_name);
...
}
...
### in some client
...
my $p = new Sub::Param($param_type_name);
$p->foo(1);
$p->bar('Toledo');
SomeLibrary::some_method($p);
...