Rod Adams wrote:

All I want now is for autothreading to be explicit.

It already *is*.

The only way that:

        is_prime($x)

can ever autothread is if $x holds a junction. But that can now only happen if there's an explicit C<use junctions> in scope where $x was assigned to (or the explicit use of some other module that also activates C<use junctions>). So $x having a junction must be a known possibility at that point.

Of course, literal junctions *will* autothread in all circumstances:

        is_prime(any(6,7,8))

        is_prime(6|7|8)

But they're both explicit too: you're explicitly using junction constructors, so the autothreading can hardly come as a surprise.

And if:

        is_prime($x)

does happen to autothread when you weren't expecting it to, then one of two things will happen. Either the subroutine will be 'pure' in which case there's no problem in autothreading it; or else the subroutine will have side effects, in which case you'll get an explicit warning when the autothreading occurs.

Junctions are just another type of scalar value. All the arguments I hear against that seem to mirror the arguments we always hear against Perl scalars being dynamically typed at all: but how will you know whether $x has a number or a string or a reference in it??? And of course the answer is: most people know most of the time, simply by paying attention to the data flow of their program. And when they occasionally mess up and accidentally give a function or subroutine the wrong kind of value, Perl usually warns them about it.

Personally, I think it's completely fascist to require a C<use junctions> pragma in order for junctions to even be stored in variables. It's as bizarre as requiring C<use strings> or C<use references> or C<use undef> or C<use infinities> would be. Yes, it *is* possible to get unexpected behaviour from passing a junction where it isn't expected, but it's already possible to get unexpected behaviour by passing a string or an undef or a reference or an object where it isn't expected. Junctions are nothing new in that respect.

I think junctions ought to be first class scalar data types and not have to ask permission before they can even be assigned. If you want to be sure that a particular variable doesn't have a junction in it, you should have to specify that, in exactly the same way you have to be explicit in order to prevent a variable storing a string or a reference or an object...by giving it an explicit type:

        my Num $x;             # Can't store a string or reference
        my Ref $y;             # Can't store a number or string
        my Nonjunctive $x;     # Can't store junctions

And where did C<Nonjunctive> come from? I created it. Ironically, by using the Awesome Power of Junctions:

        type Nonjunctive ::= none(Junction);

And if typing a variable to prevent it storing a junction is too onerous, it would still be perfectly sufficient to simply provide a C<no junctions> pragma, under whose geas no junction shall be suffered to live.

Look, I do understand the arguments in the other direction. I've understood them for the past five years that I've been developing the concept of superpositional data-types. I've thought them through numerous times myself, and in the end: I just don't buy them.

The whole point of junctions is to make the threading of operations on datasets both automatic and implicit; to make it Do The Right Thing without the hassles of explicit threading. If you don't want that, that's fine: just don't use junctions. Use arrays and hyperoperators instead. And we'll happily give you a C<no junctions> pragma so you can be emphatic about not wanting them.

But bowdlerizing the concept of junctions isn't the answer.

Damian

Reply via email to