Martin D Kealey suggested:

> Well, I think returning or throwing an "Unordered" exception would be
> the appropriate way to handle those, both for complex numbers and for
> junctions.

For complex numbers that might be true, because the order relationship
between two complex numbers isn't expressible "in-band".

But for junctions, the relationship of "sometimes <, somtimes >=" is
entirely expressible. It's just: any(True, False).


> And what about when that difference is wrapped up inside a function? In
> other words, what's wrong when I expect the following two snippets to
> work the same way?
>
>        sub anything_is_broken($subject) {
>            grep { ! .test() } $subject.parts()
>        }
>
>
>        sub everything_is_working($subject) {
>            ! grep { ! .test() } $subject.parts()
>        }
>
> Why should it make a difference whether $subject is a junction?

Because, although the two subroutines seem like they're complementary,
they actually only partition the universe when the universe is strictly
one-dimensional. And sometimes not even then.

For example, here's a *non-junctive* scalar subject for which the two
don't provide consistent answers either:

    class Part {
        has $.value;
        method test { $.value != 0 }
    }

    class Subject {
        has Part @.parts;
        method parts { @.parts.pick(2) }
    }

    my Subject $subject .= new(0..9);

    say anything_is_broken($subject);    # 0 (because .parts picked 3 and 7)
    say everything_is_working($subject); # 0 (because .parts picked 9 and 0)

In other words, it isn't the junctive-ness that creates unexpected
behaviour, it's the assumption that every scalar works the same way.


> That's not true for user-defined functions, so I think the real problem
> is that the parallelizing of the expression that contains a junction may
> not be "obvious" at the point where it happens.

But that's not a unique property of junctions; that "not obviousness"
is equally true of any scalar that, for example, simply overloads .Num
or .Str or .Bool.

For instance:

    if $result { say $result }

can easily print "0", which is not obvious, but is still both correct
and useful (when, for example, $result the result of a call to C<system>).


> Hmmm .... maybe one way to improve that might be to say that you can't
> put a junction into an untyped scalar, or indeed in any variable that
> isn't explicitly marked as "this thing might contain a junction". That
> would apply, as now, to function parameters and returns, but also to
> variables and aggregate members; indeed, *everywhere*.

But junctions are an intrinsic part of Perl 6. So it's unreasonable to
*not* expect them. And if you want to not expect them, you can just mark
your variables that way, with (ironically):

    my $subject where none(Junction);

Besides, are you also going to extend this segregation of junctions to
not allow C<0 but true> in untyped scalars either? Because how else will
you avoid the non-obviousness of:

     if $result { say $result }

???


> I don't think strong typing is enough, because we explicitly mask the
> application of type constraints by autothreading. Each thread sees a
> thing with the type it expects, but the problem comes when the threads
> are recombined; the result often won't be what's expected.

Huh? If the variables are strongly typed as non-junctive, a junction
will never be able "sneak past" into or out-of an autothreading.


> Don't get me wrong, I think Junctions are a really clever way of
> writing concise conditional expressions, but I think algebraic
> consistency is more important than clever conciseness.

Aha. I see that we mean different things when we use the term "algebraic
consistency". You seem to want all algebras to be universally
consistent; I want each algebra to be internally consistent. Or to put
it another way, you appear to want:

    A given operator or function does one consistent thing
    (regardless of the specific types of its operands)

whereas I want:

    A given operator or function does one thing
    (consistent with the specific types of its operands)

In other words, you seem to be arguing for monomorphism, whereas I'm
definitely arguing for polymorphism. Neither is inherently better, but
one is inherently more powerful. While I deeply respect your
position, I'm going to keep arguing for that more powerful alternative.

Damian

Reply via email to