The recently published article contained a factual error, as was pointed out by Elizabeth Mattijsen. I stated that named arguments do not work in role parameterization but it is not true. Yet, what I was certain about is that there is clearly something wrong about them. It took a bit of my time and wandering around Rakudo sources to recover my memories. The actual problem about named parameters is less evident and I dedicated a section of the article to explain what is actually going on.
In this post I will share more detailed explanation of what’s going on for those
interested in it. If anybody wish to follow me by watching the code open the
src/Perl6/Metamodel/ParametricRoleGroupHOW.nqp file in Rakudo sources. There
we start with method parameterize. Remember in the meanwhile, that the code is
NQP meaning it looks like Raku but it lacks many features of it.
At the end of the method we find nqp::parameterizetype op. It is described in
nqp ops
docs.
What we must pay attention to is the second parameter of the op which is named
as parameter_array. This means one simple thing: the op is only able to
recognize positional parameters.
In the documentation we also find out that for a given set of parameters the op
will return the same type parameterization. Apparently, this is how we make sure
that R[Int, "ok"] will remain the same role currying everywhere.
But what happens when named parameters are involved? To make it possible to
dispatch over them ParametricRoleGroupHOW does a trick: it takes the slurpy
hash of nameds and uses it as a single positional argument which is appended to
the end of @args array of positionals. To be consistent, if there are no nameds
are passed in, NO_NAMEDS constant is pushed instead. It is long in text, but
short in the code:
nqp::push(@args, %named_args || NO_NAMEDS);
Let’s say, we parameterize over R[Int, Str]. The @args array will be
something like:
[Int, Str, NO_NAMEDS]
No matter how many times we meet R[Int, Str] in Raku code, the @args array
will remain consistent allowing nqp::parameterize to produce a consistent
result.
But as soon as R[Int, Str, :$foo] is used the array will look like:
[Int, Str, %named_args]
where %named_args is a slurpy parameter of the parameterize method:
method parameterize($obj, *@args, *%named_args) {
Each time the method is invoked it will be a different hash object, even if the same named arguments are used! This will effectively make it look like a different set of arguments for the parameterization code. Evidently, a different parametrization will be produced too.
It is theoretically possible for the metamodel code to analyze the hash of nameds, and keep track of them, and re-use a hash if same set of arguments was previously used… But as I mentioned this in the article, the new dispatching should be able to handle things in a better and more performant way.
Comments