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


In reply to [perl6] Complex Attribute Validation and/or Triggers by duelafn

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.