Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is contains( Junction) defined?

This code works:

(3,6...66).contains( 9|21 ).say  # OUTPUT: «any(True, True)␤»

And returns a Junction. It's also tested, but not documented. The problem is I can't find its implementation anywhere. The Str code, which is also called from Cool, never returns a Junction (it does not take a Junction, either). There are no other methods contain in source. Since it's autothreaded, it's probably specially defined somewhere. I have no idea where, though. Any help?

like image 750
jjmerelo Avatar asked Apr 04 '19 06:04

jjmerelo


People also ask

What is junction example?

For example, your body has nerve junctions — the places where your nerves come together. You may go swimming at the junction of two rivers. Junction can also refer to something that connects things, like a junction you use to connect electrical cords.

What is the meaning of traffic junction?

A junction, when discussed in the context of transport, is a location where traffic can change between different routes, directions, or sometimes modes, of travel.

What is the meaning of name junction of district?

It also means that the streets or railway lines meet at a point. The junction is related to roads, canals, and rail. It also means two things are joined together which are in motion like nerve junction present in the body.


1 Answers

TL;DR Junction autothreading is handled by a single central mechanism. I have a go at explaining it below.

(The body of your question starts with you falling into a trap, one I think you documented a year or two back. It seems pretty irrelevant to what you're really asking but I cover that too.)

How junctions get handled

Where is contains( Junction) defined? ... The problem is I can't find [the Junctional] implementation anywhere. ... Since it's autothreaded, it's probably specially defined somewhere.

Yes. There's a generic mechanism that automatically applies autothreading to all P6 routines (methods, operators etc.) that don't have signatures that explicitly control what happens with Junction arguments.

Only a tiny handful of built in routines have these explicit Junction handling signatures -- print is perhaps the most notable. The same is true of user defined routines.

.contains does not have any special handling. So it is handled automatically by the generic mechanism.

Perhaps the section The magic of Junctions of my answer to an earlier SO Filtering elements matching two regexes will be helpful as a high level description of the low level details that follow below. Just substitute your 9|21 for the foo & bar in that SO, and your .contains for the grep, and it hopefully makes sense.

Spelunking the code

I'll focus on methods. Other routines are handled in a similar fashion.

method AUTOTHREAD does the work for full P6 methods.

This is setup in this code that sets up handling for both nqp and full P6 code.

The above linked P6 setup code in turn calls setup_junction_fallback.

When a method call occurs in a user's program, it involves calling find_method (modulo cache hits as explained in the comment above that code; note that the use of the word "fallback" in that comment is about a cache miss -- which is technically unrelated to the other fallback mechanisms evident in this code we're spelunking thru).

The bit of code near the end of this find_method handles (non-cache-miss) fallbacks.

Which arrives at find_method_fallback which starts off with the actual junction handling stuff.

A trap

This code works:

(3,6...66).contains( 9|21 ).say  # OUTPUT: «any(True, True)␤»

It "works" to the degree this does too:

(3,6...66).contains( 2 | '9 1' ).say  # OUTPUT: «any(True, True)␤»

See Lists become strings, so beware .contains() and/or discussion of the underlying issues such as pmichaud's comment.

Routines like print, put, infix ~, and .contains are string routines. That means they coerce their arguments to Str. By default the .Str coercion of a listy value is its elements separated by spaces:

put 3,6...18;                    # 3 6 9 12 15 18
put (3,6...18).contains: '9 1';  # True

It's also tested

Presumably you mean the two tests with a *.contains argument passed to classify:

my $m := @l.classify: *.contains: any 'a'..'f';
my $s := classify *.contains( any 'a'..'f'), @l;

Routines like classify are list routines. While some list routines do a single operation on their list argument/invocant, eg push, most of them, including classify, iterate over their list doing something with/to each element within the list.

Given a sequence invocant/argument, classify will iterate it and pass each element to the test, in this case a *.contains.

The latter will then coerce individual elements to Str. This is a fundamental difference compared to your example which coerces a sequence to Str in one go.

like image 117
raiph Avatar answered Oct 21 '22 06:10

raiph