SMOP Late Context Propagation


Perl is, historically, a context-oriented programming language. In Perl 5, the modules "overload" and "Contextual::Return" exposes the possibilities of this feature. Perl 6 takes this one step further, since the lazyness is influenced by the context in which the values are used.

The problem with all this lazyness, is that in Perl 6 it's not always possible to determine the context in which a value will be used. Perl 6 introduces the concept of Capture in place of the references in Perl 5. A reference in Perl 5 always imply scalar context, while a capture in Perl 6 is actually a way to delay the context attribution.

The most practical implication of that design is that "want" does not always have how to provide the precise information on how the value is being used.

Perl 6 also defines a new type of context, which is the Slice context, which presents some very new concepts, specially for those coming from Perl 5. For instance:

my @@slice = map { foo() }, bar();

The variable @@slice will then contain a bidimensional array where the first dimension lists every map iteration, and the second dimension contains the return of each map iteration without forcing any context on each of the iterations. This means that if foo returns (1,(2,3)), you can navigate into this values in slice context, while if you get it in List context, it will be flattened to a plain list.

What is "Late Context Propagation"

Since it's so hard to figure out the context in which some value is going to be used, in SMOP "forward context propagation" is considered an optimization, and conceptually in SMOP we assume "late context propagation", which means that the value itself is responsible to support the coercion to the specific context by implementing the appropriate method calls. This means that the return of a method works like Contextual::Return. This means that the value returned by any method call should be able to be coerced to the desired contexts.

Does that mean returning proxy objects for everything?

No. The basic idea is:

And that is implemented simply by the fact that all values that are supposed to be used in Scalar context should implement 'FETCH' returning the value itself, while every value that is supposed to be used in List context should implement 'List', 'postcircumfix:<[ ]>' and 'elems' that returns itself for the two first methods and 1 for the last.

And what about arrays?

Arrays are not Lists. This is a fundamental aspect of how Perl 6 works. Arrays are not immediatly coerced to lists, in fact:

my @a = [1,2,3];

sets the fist element of the list @a with the array as the first element. That means that array values behave just like any other value in List context.