Default value in new method causing object construction to work in an unexpected way - raku

Can someone help me understand the following behavior?
class Box {
has $.data;
multi method new($d) {
say 'here';
self.bless(data => $d);
}
}
# construct object with the custom new()
my $box = Box.new('hi');
say $box.data;
# construct object using default new()
my $box2 = Box.new(data => 'be');
say $box2.data;
This outputs:
here
hi
be
OK, perfect, exactly what is expected. However, change the code so the new method $d has a default value like this:
class Box {
has $.data;
multi method new($d = '') { # we give $d a default value now
say 'here';
self.bless(data => $d);
}
}
my $box = Box.new('hi');
say $box.data;
my $box2 = Box.new(data => 'be');
say $box2.data;
You now get this output:
here
hi
here # new method is getting called both times and $.data is not set
This is not what I expected. I figured I would get the same output as before. Can someone please explain why I don't get he same output?
UPDATE: I notice that if I change the new() signature to:
multi method new($d = '', *%_ ())
I can get things to work as expected. But I still don't understand exactly why it didn't work without *%_ () in the first place.

The two overloads of new under consideration here are yours and the one defined on the top-level type Mu. Namely,
multi method new($d)
multi method new(*%attrinit)
Or, written more explicitly,
multi method new(Box: $d?)
multi method new(Mu: *%attrinit)
But, we need to be even more explicit. Because, though it looks like only the latter should match Box.new(data => 'be'), the two are in fact both valid candidates. That's because, according to the documentation for Method,
Methods automatically capture extra named arguments into the special variable %_, where other types of Routine will throw at runtime. So
method x() {}
is actually equivalent to
method x(*%_) {}
and that applies to multi method as well. The rationale behind this is to allow methods to forward named arguments that they don't understand to their callers.
So, really, our two overloads are
multi method new(Box: $d?, *%_)
multi method new(Mu: *%attrinit)
So when we write Box.new(data => 'be'), we have two candidates which are valid, and the first one has a more specific invocant (Box rather than Mu), so it gets called.
In the case without the default argument, the candidates look like
multi method new(Box: $d, *%_)
multi method new(Mu: *%attrinit)
so the first multi is only a candidate for invocation if there's one positional argument.
We can use the trick from this Stack Overflow answer to suppress this behavior.
multi method new($d = '', *% ()) {
say "here $d";
self.bless(data => $d);
}
The *% () (the space is important here) is actually a rather neat little trick. The linked answer explains it better than I can, but basically the *% part says "I accept any named arguments", and then the () is a sub-signature to match against, namely the empty signature. You can't stop a method from accepting named arguments, so this more or less reads as "my method accepts any named arguments, as long as the list of named arguments is equal to the empty list".

Interesting question and good Answers already.
However, I think that both depend a little too much on obscure aspects of raku, namely 'bless' and '*% ()' - not to say that these tricks don't have a place, but that the common case given (a positional with default) should not need you to reach for the power tools.
Here's my solution:
class Box {
has $.data = ''; # we give data a default value here
multi method new($data) {
samewith(:$data) # redespatch positional data as named data
}
}

Related

Kotlin construction: function call with additional body - what such construction means or how it is called (if I want to look it up in the docs)?

I am seeing the Kotlin code:
navController.navigate("sales_order/" + it.toString()) {
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
launchSingleTop = true
restoreState = true
}
which I can describe as "function call" (navController.navigate) "with additional body" ({...}). How such construction is called (if I want to look it up in the docs) and what does it mean?
When I checked the type of navController.navigate(...) args, then there are 2 arguments. The first argument - string - is provided in () and I am trying to guess, that everything inside {...} is the content for the second argument which has type NavOptionsBuilder in this case. So, I can guess that NavOptionsBuilder has 3 arguments: 1 function call popUpTo that returns some object and 2 named arguments (launchSingleTop, restoreState) which are Boolean type.
Am I deciphering this construction right - just another way of passing arguments - or is there something deeper?
Am I deciphering this construction right
Almost. You got the beginning right, but the end is not exactly correct.
Let's start with what you got right, and throw in some vocabulary here for posterity. Indeed, you seem to be using the overload of navigate that takes 2 arguments: a string route and a builder function.
Functions in kotlin can be passed in multiple ways, but the most common (and the one used here) is passing a lambda expression. Because the syntax for lambda expressions is based on braces ({ ... }), it makes it look like blocks of code, so the Kotlin language went one step further and allowed to pass lambda expressions outside of the parentheses of the function call when the lambda is the last argument. The reason for this is exactly to allow this kind of constructions which look like their own configuration language. This is what is usually referred to as DSLs (Domain Specific Languages).
Now about what you got wrong:
So, I can guess that NavOptionsBuilder has 3 arguments
Not really. NavOptionsBuilder is the receiver of the function that is passed as the second argument of navigate. This means that, within the lambda that you pass, a NavOptionsBuilder instance is implicitly available as this.
This, in turn, means that you can access methods and properties of NavOptionsBuilder within that lambda block. This is what popUpTo, launchSingleTop, and restoreState are: methods and properties of NavOptionsBuilder - not "arguments".
You can find more general info about this here.

How do I capture default arguments with `|c`?

I've got this function here:
my #modifiers = <command option>;
sub triple(|c(Str:D $app1!, Str:D $app2!, Str:D $key! where .chars == 1, Str:D $mod where ($mod ~~ any #modifiers) = 'command' )) {
print_template(|c);
}
sub print_template(*#values) {
...work done here...
}
The problem I'm having is if I call it without the 4th argument, with something like triple 'App1', 'App2', 'p';, the default $mod argument does not get passed on to the print_template argument.
Is there a way to accomplish this?
For full context, this is the toy program here: https://paste.debian.net/1226675/
TL;DR 1. An explanation of the problem. 2. A DRY solution. 3. The DRYest solution: a parameters-capture function.
An explanation of the problem
A call proceeds in two steps:
Construct a call, without knowing what routine will hear the call. This includes constructing a capture of the call arguments. This capture is already done and dusted, immutable, before step 2.
See what routine candidates there are that might bind to the call. Try to bind the capture to their signatures. Some parameters in a routine's signature might specify defaults in case an argument is missing.
So, given a capture c, you can't alter it to make up for any arguments that aren't in it, and Raku doesn't automatically create a new capture that pretends any arguments that aren't in it are now in it. Instead you're going to have to manually add the missing values.
A DRY solution
The string 'command' appears twice in the suggested solution in your answer.
One way to write a DRY solution is to use the whole capture, which will include all the passed arguments, and then append any parameters for which corresponding arguments were not passed. That is to say, instead of:
my \d = \(|c[0..2], c[3] // 'command');
write this:
my \d = \(|c, |($mod if not c[3]));
The DRYest solution: a parameters-capture function
Ultimately what your scenario calls for is a function which completely ignores the arguments used to call a routine and instead just creates a new capture consisting of all of a routine's parameters. Then one could just write, say:
print_template(|parameters-capture);
That strikes me as pretty non-trivial. It would mean walking a routine's parameter data. This would presumably go via something like &?ROUTINE.signature.params. But &?ROUTINE is a compile-time variable and is relative to the current routine, so how do you get to that in a function you've called from the routine whose parameters you're interested in? And even if you can get to it, how do you get from compile-time parameter data structures to the run-time values that end up bound to the parameters? It's all way past my paygrade. It's perhaps a lot easier to do this sort of guts coding than it is in, say, the Perl world, where it means C coding, but still.
OK, based on responses in IRC, this does not appear to be possible. One suggested workaround:
sub triple(|c(Str:D $app1!,
Str:D $app2!,
Str:D $key! where .chars == 1,
Str:D $mod where ($mod ~~ any #modifiers) = 'command' )) {
my \d = \(|c[0..2], c[3] // 'command');
print_template(|d);
}
Another way to get to the same overall result (and probably the way I'd go) would be to split this out into a multi and dispatch based on the number of parameters. Here's one way that could look (with validation of the shared params moved to the proto:
my #modifiers = <command option>;
proto triple(Str:D, Str:D, Str:D $ where .chars == 1, $?) {*}
multi triple(|c($, $, $, Str:D $ where any #modifiers)) { print_template |c }
multi triple(|c($, $, $)) { print_template |c, 'command' }
sub print_template(*#values) {
# work done here
}
say triple 'App1', 'App2', 'p';

Kotlin syntax issue

Sorry for the terrible title, but I can't seem to find an allowable way to ask this question, because I don't know how to refer to the code constructs I am looking at.
Looking at this file: https://github.com/Hexworks/caves-of-zircon-tutorial/blob/master/src/main/kotlin/org/hexworks/cavesofzircon/systems/InputReceiver.kt
I don't understand what is going on here:
override fun update(entity: GameEntity<out EntityType>, context: GameContext): Boolean {
val (_, _, uiEvent, player) = context
I can understand some things.
We are overriding the update function, which is defined in the Behavior class, which is a superclass of this class.
The update function accepts two parameters. A GameEntity named entity, and a GameContext called context.
The function returns a Boolean result.
However, I do not understand the next line at all. Just open and close parentheses, two underscores as the first two parameters, and then an assignment to the context argument. What is it we are assigning the value of context to?
Based on IDE behavior, apparently the open-close parentheses are related to the constructor for GameContext. But I would not know that otherwise. I also don't understand what the meaning is of the underscores in the argument list.
And finally, I have read about the declaration-site variance keyword "out", but I don't really understand what it means here. We have GameEntity<out EntityType>. So as I understand it, that means this method produces EntityType, but does not consume it. How is that demonstrated in this code?
val (_, _, uiEvent, player) = context
You are extracting the 3rd and 4th value from the context and ignoring the first two.
Compare https://kotlinlang.org/docs/reference/multi-declarations.html .
About out: i don't see it being used in the code snippet you're showing. You might want to show the full method.
Also, maybe it is there only for the purpose of overriding the method, to match the signature of the function.
To cover the little bit that Incubbus's otherwise-great answer missed:
In the declaration
override fun update(entity: GameEntity<out EntityType>, // …
the out means that you could call the function and pass a GameEntity<SubclassOfEntityType> (or even a SubclassOfGameEntity<SubclassOfEntityType>).
With no out, you'd have to pass a GameEntity<EntityType> (or a SubclassOfGameEntity<EntityType>).
I guess that's inherited from the superclass method that you're overriding.  After all, if the superclass method could be called with a GameEntity<SubclassOfEntityType>, then your override will need to handle that too.  (The Liskov substitution principle in action!)

Mixing-in roles in traits apparently not working

This example is taken from roast, although it's been there for 8 years:
role doc { has $.doc is rw }
multi trait_mod:<is>(Variable $a, :$docced!) {
$a does doc.new(doc => $docced);
}
my $dog is docced('barks');
say $dog.VAR;
This returns Any, without any kind of role mixed in. There's apparently no way to get to the "doc" part, although the trait does not error. Any idea?
(This answer builds on #guifa's answer and JJ's comment.)
The idiom to use in variable traits is essentially $var.var.VAR.
While that sounds fun when said aloud it also seems crazy. It isn't, but it demands explanation at the very least and perhaps some sort of cognitive/syntactic relief.
Here's the brief version of how to make some sense of it:
$var makes sense as the name of the trait parameter because it's bound to a Variable, a compiler's-eye view of a variable.
.var is needed to access the user's-eye view of a variable given the compiler's-eye view.
If the variable is a Scalar then a .VAR is needed as well to get the variable rather than the value it contains. (It does no harm if it isn't a Scalar.)
Some relief?
I'll explain the above in more detail in a mo, but first, what about some relief?
Perhaps we could introduce a new Variable method that does .var.VAR. But imo this would be a mistake unless the name for the method is so good it essentially eliminates the need for the $var.var.VAR incantation explanation that follows in the next section of this answer.
But I doubt such a name exists. Every name I've come up with makes matters worse in some way. And even if we came up with the perfect name, it would still barely be worth it at best.
I was struck by the complexity of your original example. There's an is trait that calls a does trait. So perhaps there's call for a routine that abstracts both that complexity and the $var.var.VAR. But there are existing ways to reduce that double trait complexity anyway, eg:
role doc[$doc] { has $.doc is rw = $doc}
my $dog does doc['barks'];
say $dog.doc; # barks
A longer explanation of $var.var.VAR
But $v is already a variable. Why so many var and VARs?
Indeed. $v is bound to an instance of the Variable class. Isn't that enough?
No, because a Variable:
Is for storing metadata about a variable while it's being compiled. (Perhaps it should have been called Metadata-About-A-Variable-Being-Compiled? Just kidding. Variable looks nice in trait signatures and changing its name wouldn't stop us needing to use and explain the $var.var.VAR idiom anyway.)
Is not the droid we are looking for. We want a user's-eye view of the variable. One that's been declared and compiled and is then being used as part of user code. (For example, $dog in the line say $dog.... Even if it were BEGIN say $dog..., so it ran at compile-time, $dog would still refer to a symbol that's bound to a user's-eye view container or value. It would not refer to the Variable instance that's only the compiler's-eye view of data related to the variable.)
Makes life easier for the compiler and those writing traits. But it requires that a trait writer accesses the user's-eye view of the variable to access or alter the user's-eye view. The .var attribute of the Variable stores that user's-eye view. (I note the roast test has a .container attribute that you omitted. That's clearly now been renamed .var. My guess is that that's because a variable may be bound to an immutable value rather than a container so the name .container was considered misleading.)
So, how do we arrive at $var.var.VAR?
Let's start with a variant of your original code and then move forward. I'll switch from $dog to #dog and drop the .VAR from the say line:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a does role { has $.doc = $docced }
}
my #dog is docced('barks');
say #dog.doc; # No such method 'doc' for invocant of type 'Array'
This almost works. One tiny change and it works:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var does role { has $.doc = $docced }
}
my #dog is docced('barks');
say #dog.doc; # barks
All I've done is add a .var to the ... does role ... line. In your original, that line is modifying the compiler's-eye view of the variable, i.e. the Variable object bound to $a. It doesn't modify the user's-eye view of the variable, i.e. the Array bound to #dog.
As far as I know everything now works correctly for plural containers like arrays and hashes:
#dog[1] = 42;
say #dog; # [(Any) 42]
say #dog.doc; # barks
But when we try it with a Scalar variable:
my $dog is docced('barks');
we get:
Cannot use 'does' operator on a type object Any.
This is because the .var returns whatever it is that the user's-eye view variable usually returns. With an Array you get the Array. But with a Scalar you get the value the Scalar contains. (This is a fundamental aspect of P6. It works great but you have to know it in these sorts of scenarios.)
So to get this to appear to work again we have to add a couple .VAR's as well. For anything other than a Scalar a .VAR is a "no op" so it does no harm to cases other than a Scalar to add it:
multi trait_mod:<is>(Variable $a, :$docced!) {
$a.var.VAR does role { has $.doc = $docced }
}
And now the Scalar case also appears to work:
my $dog is docced('barks');
say $dog.VAR.doc; # barks
(I've had to reintroduce the .VAR in the say line for the same reason I had to add it to the $a.var.VAR ... line.)
If all were well that would be the end of this answer.
A bug
But something is broken. If we'd attempted to initialize the Scalar variable:
my $dog is docced('barks') = 42;
we'd see:
Cannot assign to an immutable value
As #guifa noted, and I stumbled on a while back:
It seems that a Scalar with a mixin no longer successfully functions as a container and the assignment fails. This currently looks to me like a bug.
Not a satisfactory answer but maybe you can progress from it
role doc {
has $.doc is rw;
}
multi trait_mod:<is>(Variable:D $v, :$docced!) {
$v.var.VAR does doc;
$v.var.VAR.doc = $docced;
}
say $dog; # ↪︎ Scalar+{doc}.new(doc => "barks")
say $dog.doc;  # ↪︎ barks
$dog.doc = 'woofs'; #
say $dog; # ↪︎ Scalar+{doc}.new(doc => "woofs")
Unfortunately, there is something off with this, and applying the trait seems to cause the variable to become immutable.

How does a Perl 6 object find a multi method that might be in a parent class or role?

Consider this example where a subclass has a multi method with no signature and one with a slurpy parameter:
class Foo {
multi method do-it { put "Default" }
multi method do-it ( Int $n ) { put "Int method" }
multi method do-it ( Str $s ) { put "Str method" }
multi method do-it ( Rat $r ) { put "Rat method" }
}
class Bar is Foo {
multi method do-it { put "Bar method" }
multi method do-it (*#a) { put "Bar slurpy method" }
}
Foo.new.do-it: 1;
Foo.new.do-it: 'Perl 6';
Foo.new.do-it: <1/137>;
Foo.new.do-it;
put '-' x 10;
Bar.new.do-it: 1;
Bar.new.do-it: 'Perl 6';
Bar.new.do-it: <1/137>;
Bar.new.do-it: 5+3i;
Bar.new.do-it;
How is the method lookup structured? I'm looking more for a way to explain it and specifically not complaining about it.
Int method
Str method
Rat method
Default
----------
Int method
Str method
Rat method
Bar slurpy method
Bar method
There's a call to Bar's do-it with 1 for instance. Some reasonable people might think that it looks for a matching signature in Bar first and that slurpy would never let anything get past it. Yet, the call finds the right multi in the inheritance chain.
Does Bar already know all the signatures? Does it search or is all of that stuff already resolved when it is composed?
And, is there a way to find out at run time which class provided the method? Maybe with some call into HOW? This would be a handy debugging tool when I have a multi I've incorrectly specified and is being handled elsewhere.
The key thing to keep in mind with multiple dispatch is that it happens after sub or method resolution has taken place. So all multiple dispatch is actually a two step process. The two steps are also independent of each other.
When writing something like:
multi sub foo($x) { }
multi sub foo($x, $y) { }
The compiler will generate a:
proto sub foo(|) {*}
That is, unless you wrote a proto sub by yourself. The proto is what actually gets installed into the lexpad; a multi sub is never installed directly into the lexpad, but instead installed into the candidates list of the proto.
So, when calling a multi sub, the process is:
Find the sub to call using a lexical lookup, which resolves to the proto
Call the proto, which picks the best multi candidate and calls it
When there are multi candidates in nested scopes, the proto from an outer scope will be cloned and installed into the inner scope, and the candidate added to the clone.
A very similar process happens with multi methods, except:
Multi methods are just stored up in a todo list until the closing } of the class, role, or grammar
A proto may be provided by a role or a class, so composing a role with multi candidates just adds them to the todo list also
Finally, if there is multi methods with no proto, but a parent class has such a proto, that will be cloned; otherwise an empty proto will be made
Meaning that a call to a multi-method is:
Find the method using the usual method dispatch algorithm (which just searches classes using the C3 Method Resolution Order), which resolves to the proto
Call the proto, which picks the best multi candidate and calls it
The exact same sorting and selection algorithm are used for both multi subs and multi methods. The invocant, so far as the multiple dispatch algorithm cares, is just the first parameter. Furthermore, the Perl 6 multiple dispatch algorithm does not weight earlier arguments more heavily than later ones, so just as:
class A { }
class B is A { }
multi sub f(A, B) { }
multi sub f(B, A) { }
Would be considered tied, and give an ambiguous dispatch error if called with f(B, B), so would defining:
class B { ... }
class A {
multi method m(B) { }
}
class B is A {
multi method m(A) { }
}
And then calling B.m(B), since again the multi-dipsatcher just sees the type tuples (A, B) and (B, A).
Multiple dispatch itself is concerned with the concept of narrowness. A candidate C1 is narrower than C2 if at least one argument of C1 is a narrower type than the argument in the same position in C2, and all other arguments are tied (that is, not narrower, not wider). If the inverse is true then it is wider. Otherwise, it is tied. Some examples:
(Int) is narrower than (Any)
(Int) is tied with (Num)
(Int) is tied with (Int)
(Int, Int) is narrower than (Any, Any)
(Any, Int) is narrower than (Any, Any)
(Int, Any) is narrower than (Any, Any)
(Int, Int) is narrower than (Int, Any)
(Int, Int) is narrower than (Any, Int)
(Int, Any) is tied with (Any, Int)
(Int, Int) is tied with (Int, Int)
The multi-dipsatcher builds a directed graph of the candidates, where there is an edge from C1 to C2 whenever C1 is narrower than C2. It then finds all of the candidates with no incoming edges, and removes them. These are the first group of candidates. The removal will produce a new set of candidates with no incoming edges, which are then removed and become the second group of candidates. This continues until all candidates are taken from the graph, or if we reach a state where we can take nothing from the graph (a very rare situation, but this will be reported to the programmer as a circularity). This process happens once, not per dispatch, and it produces a set of groups of candidates. (Yes, it is just a topological sort, but the grouping detail is significant for what comes next.)
When a call happens, the groups are searched in order for a matching candidate. If two candidates in the same group match, and there are no tie-breakers (named parameters, where clauses or implied where clauses from subset types, unpacks, or is default) then an ambiguous dispatch will be reported. If all the groups are searched without a result being found, then the dispatch fails.
There are also some narrowness considerations with regard to arity (required parameter beats optional parameter or slurpy) and is rw (it's narrower than an otherwise equal candidate without is rw).
Once one or more candidates in a group have been found to match, then tie-breakers are considered. These include the presence of named parameters, where clauses, and unpacks, and work on a first-match-wins basis.
multi f($i where $i < 3) { } # C1
multi f($i where $i > 1) { } # C2
f(2) # C1 and C2 tied; C1 wins by textual ordering due to where
Note that this textual ordering is only applicable to the tie-breaking; so far as types go, the order of candidates in the source code is not important. (That named parameters also act only as tie-breakers is sometimes a source of surprise.)
Finally, I'll note that while the results of a multiple dispatch will always match the 2-step process I've described, in reality a good amount of runtime optimization takes place. While all lookups are initially resolved exactly as described, the outcome is placed into a dispatch cache, which provides much faster lookups than searching the groups delivered by the topological sort could. This is installed in such a way that the call of the proto can be entirely bypassed, saving a callframe. You can see artifacts of this behavior if you --profile; the auto-generated proto for any type-based dispatch (without tie-breakers) will receive a tiny number of calls compared to the multi candidates. This doesn't apply if you write custom logic in your proto, of course.
Beyond that, if you're running on MoarVM, the dynamic optimizer can go a bunch further. It can use collected and inferred type information both to resolve the method/sub dispatch and the multi dispatch, turning a 2-step process into a 0-step process. Small candidates can be inlined into the caller also (again, the profiler can tell you that the inlining has happened), which arguably turns a multi-dispatch into a -1 step process. :-)
The Rakudo Perl 6 method look up process is done by the Metamodel::MROBasedMethodDispatch role by default. See Rakudo's /src/Perl6/Metamodel/MROBasedMethodDispatch.nqp for the corresponding source code.
(Which, in turn, by default, uses role Metamodel::C3MRO, which implements C3 method resolution order. See Rakudo's /src/Perl6/Metamodel/C3MRO.nqp for the source code.)
.^find_method returns a matching method based on a short name (without parameters). Whenever the short name corresponded to multiple methods this returned method is a proto.
Calling .candidates on a proto returns a list of Method objects that match the proto. (Calling .candidates on a non-proto method just returns that same method as the only element in a one element list.)
for Bar.^find_method('do-it').candidates -> $method {
$method.signature.say;
}
which gives:
(Foo $: *%_)
(Foo $: Int $n, *%_)
(Foo $: Str $s, *%_)
(Foo $: Rat $r, *%_)
(Bar $: *%_)
(Bar $: *#a, *%_)
The Bar.new.do-it: 5+3i; call passes a Bar as self plus the 5+3i positional argument. The signature from the candidate list that's closest to those arguments (aka "narrowest matching") is the (Bar $: *#a, *%_) one. So the routine with that signature gets called.
The Bar.new.do-it; call passes a Bar as self and nothing else. The (Bar $: *%_) signature is an even closer (narrower) match than (Bar $: *#a, *%_). Again, the routine with the closest (narrowest) signature gets called.