duelafn has asked for the wisdom of the Perl Monks concerning the following question:
Are there ways in perl6 to write more complex attribute validators and/or before/after/around modifiers on attribute access? I can't seem to find anything that would let me, say, implement an interval class with a lower and upper bound, or call some code every time an attribute is changed. Did I miss it somewhere?
class Interval { has Real $.lb is rw = die 'Lower bound is required'; has Real $.ub is rw = die 'Upper bound is required'; } ### Example which does not work: # class Interval { # has Real $.lb where * <= $.ub is rw = die 'Lower bound is requir +ed'; # has Real $.ub where * >= $.lb is rw = die 'Upper bound is requir +ed'; # after lb { say "Lower bound was changed!" if @_ } # } my $i = Interval.new( lb => 1, ub => 3); say $i.perl; $i.lb = 0; # should print message say $i.perl; $i.lb = 6; # should blow up! say $i.perl;
Update: Thanks all, tye makes a great point about the folly of such a design and raiph hunted down some additional options — though implemented as lvalue methods, we can not distinguish reading from writing.
To me, it looks like the is rw trait on attributes should, in most cases, be avoided. Using it does limit what you are able to validate (fundamentally, not due to language shortcomings). Thus a recommended alternate implementation:
class Interval { has Real $.lb = die 'Lower bound is required'; has Real $.ub = die 'Upper bound is required'; method update(:$lb = $.lb, :$ub = $.ub) { die "Require lb <= ub" unless $lb <= $ub; ($!lb, $!ub) = ($lb, $ub); } }
And if one really wants independent validating setters or distinct
read/write triggers, we have to implement both ourselves and must use
method call notation (no lvalue $i.lb = 6 syntax). Update: Apparently there is, in fact, a way to save the lvalue syntax, though the linked lvalue approach doesn't seem to be working currently. Here is the method-based approach:
class Interval { has Real $.lb = die 'Lower bound is required'; has Real $.ub = die 'Upper bound is required'; multi method lb() { $!lb } multi method lb($lb) { die "Require lb <= ub" unless $lb <= $!ub; $!lb = $lb; } multi method ub() { $!ub } multi method ub($ub) { die "Require lb <= ub" unless $!lb <= $ub; $!ub = $ub; } }
Good Day,
Dean
|
|---|