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