Raku / problem-solving

🦋 Problem Solving, a repo for handling problems that require review, deliberation and possibly debate
Artistic License 2.0
69 stars 16 forks source link

Support for custom HOWs isn't generic enough #90

Open Kaiepi opened 4 years ago

Kaiepi commented 4 years ago

This issue is specific to creating custom parametric knowhows. A library I'm working on depends on being able to do this, since roles don't behave the way I need them to. I'm leaving this issue more general though, in case other people have found other cases where support for custom knowhows isn't ideal.

Rakudo supports creating custom knowhows and making it possible to use them as declarators using EXPORTHOW::SUPERSEDE and EXPORTHOW::DECLARE. Making a knowhow itself be parametric is fairly straightforward; just ensure it has the parametric archetype and has a parameterize method, from what I gather. The problems start once you actually try to use the declarator you assigned to the knowhow though.

If you're using EXPORTHOW::DECLARE, you need to write a slang to override the grammar's package_def rule because it's hard-coded to only allow roles to be parametric. Since package_def handles all package definitions without multiple dispatch, only one module can override it at a time. You can't add custom references to knowhows like ::?PACKAGE and $?PACKAGE without overriding the package_def rule either.

EXPORTHOW::SUPERSEDE is more lenient since it allows overriding declarators other than package declarators, but still has the same issue EXPORTHOW::DECLARE has when it comes to package declarators in particular. If you want to make something like parametric subsets, which don't use a package declarator, it's even more difficult to accomplish, but for the wrong reasons. Most of the code dealing with signatures for parametric types is locked away in lexical routines in Perl6::Actions, meaning you need to copy several hundred lines of code just to deal with the signature used when declaring a parametric type using your custom knowhow.

Overall, this doesn't make it impossible to implement custom parametric knowhows, but it makes them very annoying to write and makes their code more fragile than it should be. Should the code for handling knowhows be made more generic and less opinionated about how they're supposed to be used? If so, how?

JJ commented 4 years ago

Are you talking about HOWs? That's an acronym for Higher Order Working, not related (not too much) with knowing HOW to build a class or something... When reading knowhows, I thought you were talking about tutorials.

Kaiepi commented 4 years ago

Yeah, that's what I mean.

jnthn commented 4 years ago

If you're using EXPORTHOW::DECLARE, you need to write a slang to override the grammar's package_def rule because it's hard-coded to only allow roles to be parametric.

Is the issue here really that it only parses a signature if the package declarator is role, and that instead we should look at a property from the archetypes to decide whether to parse one? That's probably quite easy to do, though the meta-object in question had then better be ready to handle the set_body_block call and similar.

Kaiepi commented 4 years ago

Is the issue here really that it only parses a signature if the package declarator is role, and that instead we should look at a property from the archetypes to decide whether to parse one?

In part, but I don't think that alone is good enough. I've made more progress with the project that led me to start this issue (which requires not one, but two parametric HOWs), and I noticed that besides the inlined code in package_def, none of the syntax needed to change, and on top of that, there's a lot in common with what they do in their inlined code. The key differences between them are:

This leads me to think how the types created should be handled is something that may be possible to fix by making it possible to configure what traits package declarations for HOWs have. If this is possible, no changes to how package declarations are parsed would be needed. A default configuration for a HOW's declaration that matches how they're handled currently would prevent a fix for this from potentially breaking any existing code that depend on package_def.

though the meta-object in question had then better be ready to handle the set_body_block call and similar.

The two I mentioned, as well as an unrelated third one for an ecosystem module I plan on releasing soon (which mixes in support for parameterization into an existing HOW without adding any new syntax), all use body blocks. I think a metarole providing support for body blocks might be useful to have for this.

Kaiepi commented 4 years ago

Configurations for HOWs would fix another issue I encountered: I don't think making Metamodel::Primitives methods for parametric type ops is possible to do in an ideal way at the moment. Roles' parametric HOWs, Metamodel::DefiniteHOW, and Metamodel::CoercionHOW have different rules for how they handle creating their parameter list to pass to nqp::parameterizetype and retrieve from nqp::typeparameters. Not all of the parameters they pass to it can be HLLized, to the best of my knowledge. If they had a configuration for how they handle storing and retrieving their parameters, then I think methods for nqp::parameterizetype, nqp::typeparameters, and nqp::typeparameterat would be possible to write in such a way that the parameter(s) they return don't require you to know any implementation details of how they handle this.