use v6.c;
class Token {
has $.type;
has $!id;
method id is rw {
Proxy.new(
FETCH => -> $ { $!id },
STORE => -> $, $nv {
if $nv ~~ $.type {
$!id = $nv;
} else {
die "Not a { $.type.^name } value.";
}
}
);
}
}
my $inty = Token.new(:type(Int));
my $stry = Token.new(:type(Str));
$inty.id = 10;
say $inty.id;
$stry.id = 'AA';
say $stry.id;
try {
$inty.id = 'AA';
CATCH {
default { .message.say }
}
}
try {
$stry.id = 11;
CATCH {
default { .message.say }
}
}
And the armchair explanation:
<Xliff> OK, let me explain.
<Xliff> In Perl6, it's best to leave type constraints until as late as possible.
<lookatme_q> Maybe using the type parameter role
<lookatme_q> https://docs.perl6.org/language/objects#index-entry-Parameterized_Roles
<Xliff> so we start with: "class Token { has $.typel has $!id; ... }
<Xliff> $.type and $!id are not typed. This is important.
<Xliff> Given that $!id means "private member", so we have to create a way to access ID.
<Xliff> Hence "method id is rw".
<Xliff> Saying "$inty = 10" is the same as saying "$inty.STORE(10)"
<Elronnd> ok
<Xliff> Correction... Saying "$inty.id = 10" is the same as saying "$inty.id.STORE(10)"
<Xliff> For the sake of this conversation, at any rate.
<Xliff> So that "10" value is passed to $nv in the STORE part
<Xliff> When we initialized $inty, we did so like this "my $inty = Token.new(:type(Int))"
<Xliff> That created a new Token object with $.type set to the type object Int.
<Xliff> Following?
<Elronnd> yes
<Xliff> So when any Token object sets the id value, it is smartmatched against the type object stored in the type attribute
<Xliff> What is unsaid here is that $!type MUST be a Perl6 type object.
<Xliff> That way it Just Works.
<lookatme_q> m: role Token[::T] { has T $.id; }; say Token[Int].new(id => 123); say Token[Int].new(id => "123");
<camelia> rakudo-moar 83f0fd6c9: OUTPUT: «Token[Int].new(id => 123)Type check failed in assignment to $!id; expected Int but got Str ("123") in block <unit> at <tmp> line 1»
<Elronnd> ahhh ok, that makes sense
<Elronnd> (can we add a setter for $.type to make sure it's a type object? :P)
<lookatme_q> Maybe you can consider the type parameterized role ^^ Elronnd
<Xliff> Elronnd: lookatme_q Just put up a much more efficient way of doing this with a role
<Xliff> Elronnd: Ah! Good that you mentioned "setter".
<Xliff> What I did in the ID method is pretty much the way you would implement get/set methods in Perl6.
<Xliff> Proxy FETCH ==> gety
<Xliff> Proxy STORE ==> set