in reply to Re: [perl6] Complex Attribute Validation and/or Triggers
in thread [perl6] Complex Attribute Validation and/or Triggers

Indeed it is fun. I love the language and now with Inline::Perl5 the number of projects I'm willing to try it out on is greatly increased!

Thanks for all your research and link to proxys. Indeed, it looks like these can save us if we were to create a class with a publicly writable attribute which really should have been implemented as a method. And, indeed there do seem to be bugs lurking still. I can't quite get it to work now, but am sufficiently satisfied that something like this will eventually:

class Interval { has Real $.lb = die 'Lower bound is required'; has Real $.ub = die 'Upper bound is required'; method lb() is rw { return Proxy.new: FETCH => method () { return $!lb; }, STORE => method ($lb) { die "Require lb <= ub" unless $lb <= $!ub; $!lb = $lb; }; } method ub() is rw { return Proxy.new: FETCH => method () { return $!ub; }, STORE => method ($ub) { die "Require lb <= ub" unless $!lb <= $ub; $!ub = $ub; }; } }

Good Day,
    Dean

Replies are listed 'Best First'.
Re^3: [perl6] Complex Attribute Validation and/or Triggers
by raiph (Deacon) on Mar 11, 2015 at 03:48 UTC
    Updated with info about bug. Moved Interop section to its own post.

    Glad to hear you're having fun. :)

    if we were to create a class with a publicly writable attribute

    All attributes are private. No matter what. All public access is via public methods. Another comment covers this in more detail.

    I can't quite get it to work now:

    After some digging I've concluded that one should not use `method` as the routine declarator for the value of the FETCH and STORE arguments to the Proxy but rather `sub`:

    # This is NOT a good way to validate for this use case. # But this code works in my current Rakudo. class Interval { has $.lb = die 'Lower bound is required'; has $.ub = die 'Upper bound is required'; method lb() is rw { return Proxy.new: # note `sub` declarator and ignored arg: FETCH => sub ($) { return $!lb; }, # note `sub` declarator and ignored (first) arg STORE => sub ($, $lb) { die "Require lb <= ub" unless $lb <= $!ub; $!lb = $lb; }; } method ub() is rw { return Proxy.new: FETCH => sub ($) { return $!ub; }, STORE => sub ($, $ub) { die "Require lb <= ub" unless $!lb <= $ub; $!ub = $ub; }; } }

    Using the `method` declarator as a FETCH or STORE routine isn't useful because the self in the called routine (passed in as the first arg, corresponding to the anonymous `$` parameter in the above declarations) would not be the enclosing class.

    Update Has been discussed on #perl6. jnthn landed a fix for a couple of related bugs a few hours later. Your code still won't work though; fixing it will apparently have to wait for now.