Coercion/type checking: manually reproduce Perl6 standards
Asked Answered
S

1

10

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:

  1. 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 provides FALLBACK very unclear error message (the one about AUTOGEN) is produced. :no_fallback is desirable, but definite and subset types have their own find_method which doesn't support named parameters and I end up with another error message.
  2. If a prepare type-related attributes ($!coerce-type) in compose method of my trait role applied to the Attribute 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.
  3. Is there any better way to perform type-check than $value ~~ $type?
Sonatina answered 31/8, 2018 at 14:33 Comment(2)
I’m voting to close this question because I think it's too broad and complex to leave open and it's not suitable to ask the questioner (vadim) to revise it because, as they themselves long ago wrote in a comment on my just now deleted (for a second time) nanswer, "I think this question could be sent to archive".Holophytic
Agree and closing.Sonatina
B
2

[Comments indicate that this out-of-date question was supposed to be closed in 2020 but it never was. Here's a very brief answer in case someone comes across this.]

Sometime after asking this question, the asker significantly revised Raku's coercion mechanism. See Report on New Coercions. This new syntax for coercion is in the docs.

Using this new style, the following line from the question:

my Array[Str] $a = ["a", "b", "c"];
say $a;
# OUTPUT: Type check failed in assignment to $a; 
#         expected Array[Str] but got Array ($["a", "b", "c"])

becomes

my Array[Str]() $a = ["a", "b", "c"];
say $a;
# OUTPUT: [a b c]

(That is, Array[Str]() means "something that can be coerced into an Array of Strings". That's different from Array[Str()] ("an Array of things that can be coerced to Strings") and from Array[Str()]() ("something that can be coerced into an Array of things that can be coerced into Strings").)

Similarly, the following part of the question now has an answer:

is there a single entry point used by the assignment operator which does all the coerce/typecheck? Ideally I would simply [define how a type is coerced into my type]

With the new coercion protocol, the "single entry point" is the COERCE method, which users can define for their types to teach Raku how to coerce into those types.

Bukharin answered 15/9, 2022 at 19:47 Comment(1)
It's truly amazing to get an answer to your own old question and the answer refers to what's been done by yourself. The circle is complete now. :)Sonatina

© 2022 - 2024 — McMap. All rights reserved.