Day 3 – cap your junctions

Day 3 – cap your junctions

“With great power comes great responsibility.” These days I muse on how this applies not just to movie superheroes, but to programming language features as well.

It happens all over the place. Database connection? Awesome. Well, until you become the victim of an SQL injection or a SELECT N+1 problem. Regular expressions? Also awesome… until someone uses it to parse HTML and gets a visitation from elder non-beings from beyond the fabric of reality. Ouch.

Of course, we still like our powerful features. But we need to learn to contain them, to harness them. The awesome should work for us and the purpose we have set it to. It should not work for attackers, elder non-beings, or Murphy. We need to make sure the awesome doesn’t leak beyond its designated boundaries.

In 2009, Matthew Walton blogged about junctions. His explanation of what makes junctions exciting is great, and I agree with it. Today I would simply like to add the following point: junctions are so awesome that they should be contained.

Let’s demonstrate the problem real quickly.

> my @list = 3..7
3 4 5 6 7
> my $answer = all(@list) > 0;

Quick, what value ends up in $answer? Well, all the values in @list are
indeed greater than 0, so…

all(True, True, True, True, True)

Aw, dang. Not again.

Just to be clear, this is by spec, and correctly implemented and everything. But unless you ask specifically for Perl 6 to collapse the junction, it just keeps on going. Keeps on going, like a juggernaut, through walls and oceans, propagating through your program whether you want it to or not.

What you have to do then is to collapse the junction, putting a cap on all that awesome. The junction is useful as long as you’re doing the junctive computation itself (in this case all(@list) > 0), but immediately after that, we’ll want to collapse back into the normal, sane, non-junctive world:

> ?$answer      # symbolic prefix
True
> so $answer    # listop prefix
True
> $answer.Bool  # coerce method
True

Moritz points out that the whole “collapsing” metaphor comes from quantum physics, where something collapses as it’s measured. The analogy holds up; after we’re done junctioning around with our “quantum” superposition, we want to get a single boolean value back out. We do that by “measuring” — boolifying — the junction.

I will hasten to add that the most common use of junctions doesn’t suffer from this problem, namely junctions in if statements:

if all(@list) > 0 {
...
}

The if statement itself provides a natural cap to the junction. It does its own boolification of it under the hood, but more importantly, the junction value doesn’t stick around. We only see the effects of the boolean value of the junction.

No, the real risk comes when you’re a library writer, and you provide routines that happen to compute things using junctions:

sub all-positive(@list) {
    all(@list) > 0;     # DANGER
}

That’s where you want to remember the old tired adage. With great power… comes… right, that’s right. So you cap your junction before you let it run out into the wild and do untold structural damage to people, buildings, cattle, and those cute fluffy dogs that would otherwise suffer Puppy Death By Junction.

sub all-positive(@list) {
    so all(@list) > 0;
}

Yes. That’s better.

If you declare your return type, you can get a runtime error for leaving out the `so`.

sub all-positive(@list --> Bool) {
    all(@list) > 0;
}

say all-positive([1, 2, 3]); # Type check failed for return value;
                             # expected 'Bool' but got 'Junction'

Maybe that’s an argument for declaring return types for your routines. And maybe some day we’ll catch that one at compile-time, too.

Cap your junctions as early as possible.
— masak’s Rule of Responsible Junction Use

The longest I can remember legitimately keeping junctions around in an uncollapsed state was when storing junctions of regexes in a hash as part of this password-analyzing script. Even that’s not an exception to the above rule, though — note that the first thing that happens to the junctions in the subsequent code is that they become the rhs in a smartmatch statement, and then get capped by an if statement. So even here, they don’t escape out into the wild.

Code responsibly. Cap your junctions.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s