I have a Module AttrX::Mooish
which implements some of attribute features of Moo/Moose frameworks (lazyness, trigger, etc.). I also wanted the module to be as transparent to the end user as possible meaning support for both private and public attributes. It works by replacing attribute's container with a Proxy
and storing its value in external storage. It also means that all the type checking and coercion Perl6 was doing is now my responsibility. My target is to mimic the default behavior is much as possible. I.e. for the end user:
has MyClass @foo is mooish(...);
must work the same as it would without the trait applied. Unfortunately, the subject of type manipulations is so much complicated and ununified in the language core that the more problems I fix the more problems I get afterwards. For example:
my Str @a = <a b c>; my Str @b = [1,2,3]
Type check failed in assignment to @b; expected Str but got Int (1)
As expected.
my Str @a; say @a.WHAT
(Array[Str])
Sure.
my Array[Str] $a = ["a", "b", "c"];
Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])
Well....
my Array[Str] $a = <a b c>;
Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))
Not even coercing List
to Array
!
No wonder that the final typecheck line in my trait code:
$coerced-value ~~ $attr.type
Fails here and there despite same values/types used in variable/attribute assignments work OK.
I have a question with no hope of getting any positive answer to it: is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply:
$value = coerce($value, $type);
check-type($value, :type($attr.type), :name($attr.name))
I tried to trace down from the grammar, but haven't got enough spare time to complete this yet. Besides, it is mostly nqp which I don't know and can't really understand.
But since the existence of such entry point(s) is unlikely I would like to ask for any advises related to this area. Like, for example, SmokeMachine on #perl6 provided me with a great idea of obtaining base type of a parametrized type using .^parents
method.
So far, the biggest problems are with:
- To check if type is parametrized I can't use a single role or class to match against. So far the only approach I have is by finding if there is
of
method and testing its output. Unfortunately, if a class providesFALLBACK
very unclear error message (the one about AUTOGEN) is produced.:no_fallback
is desirable, but definite and subset types have their ownfind_method
which doesn't support named parameters and I end up with another error message. - If a prepare type-related attributes (
$!coerce-type
) incompose
method of my trait role applied to theAttribute
object (where actually the attributes are declared) I find them later at run-time unitialized. Guessing its something related to compose time. But wanna be sure if nothing is missed here. - Is there any better way to perform type-check than
$value ~~ $type
?