package Tie::Constrained; #### use Errno qw/EINVAL EDOM ERANGE/; sub TIESCALAR { my $class = shift; my $self = { test => defined $_[0]? $_[0]: \&validate }; $self->{test}($_[1]) or invalid(EINVAL) if defined $_[1]; $self->{val} = $_[1]; bless $self, $class; } sub STORE { my ($self, $try) = @_; $self->{test}($try) or invalid(EINVAL); $self->{val} = $try; } sub FETCH { $_[0]->{val}; } sub DESTROY {} sub validate { 1 } sub invalid { $! = shift; die sprintf("Constraint violation: %s by %s::%s in %s line %s.\n", $!, map { qq($_) } (caller 1)[0,3,1,2] ); } 1; __DATA__ #### Usage: use Tie::Constrained; tie my $var, Tie::Constrained => \&mytest, $initval; Both arguments are optional, but the default validator function always says yes. mytest() should be designed to return true for valid data and false for data to reject.