Right up front, let me establish the setting for our Journey.

First, there are two blog articles that I’ve come across,

Secondly, here’s some code I’ve recently written (and redacted for publishing). Let me call attention to lines 22-25:

And with it, a small illustrative Test Suite:

With that all being established, let me toe the line.

GOTO is bad

We all know this to be true.

GOTO cannot be trusted. This is because GOTO has no moral compass whatsoever. GOTO will stand there in a black stove-pipe hat & cloak, glaring at you, curling its mustached menacingly. Then, with a ghoulish cackle, GOTO will tie your innocent, helpless code to the railroad tracks.

GOTO is the bane of our existence. There can be no doubt of this. The GOTO construct – and by association, labels in general – is reprehensible. Its use should be considered a Faustian bargain from which there can be no possible hope of benefit or redemption.

And hooray – I get my Merit Badge! And I take it home, and I proudly sew this new Badge onto my sash, just to the left of “Indent with Spaces”, and below “eval is Evil”.

But, deep inside of me there is a twinge of guilt. For I do not believe this dictum to be true in all cases. I would even go so far as to say that, sometimes, a label is the right tool for the job.

You Can’t Be Serious

Oh yeah, I went there.

Of course, GOTO was pretty essential back in my BASIC days, a time commonly known as “the 1980s”.

I can’t tell you how delighted I would have been to make a Git GIST of some of my old BASIC code. However, I couldn’t find any in my archive.

I imagine it’s all sitting on dessicated cassette tapes, packed away somewhere (along with my CoCo) by my loving mother.

But let’s not get all weepy & sentimental for the good old days. We’re here to talk about GOTO’s enabler, the label. And although the label is entirely complicit in the despicable actions of GOTO, that does not mean that it cannot be reformed with the help of a little :two_hearts: T.L.C.

I am not going to provide an exhaustive language survey here. Rather, the two practical examples that come to mind are;

A contrived (and unconvincing) example of the Ruby syntax is;

My quick search for a prefab Ruby example led me to this Reddit post, in which the Commenters observe;

[throw/catch is] … basically a GOTO with an optional payload.

The academic answer: raise/rescue is meant for handling exceptional conditions, NOT for control flow. If you want control flow to be able to jump locations (multiple loops, method calls, etc–those not handled by regular conditionals), then you should use throw/catch.

Now of course, not every shit-upon language feature has situational value. I’m wary of the “optional payload” part of Ruby’s syntax (thus I am not demonstrating it).

As far as JavaScript goes … you won’t catch me using a with statement – nor linking to its MDN documentation – and I avoid iterating on Strings as if they were Arrays. Sure, I could … but I won’t.

However, I would propose that, discretionally,

  • a labeled block is an effective tool for flow control

Heresy!

Hey, hey. Easy. You’ve read this far … now, hear me out.

Let me break down the essence of why & how I have used this nefarious and much maligned labeled statement syntax in my JavaScript parsing code example.

The Code Has Three Phases

  1. decode the URL, which can throw an Error
  2. progressively determine how to derive { id } from the URL
  3. return a consistent payload

Each phase is rather compact. At current length, I feel it reads nicely.

I Was Careful in My Choice of Naming

Let us take another look at lines 22-25;

processed: {
  if (! DOMAINS.has(hostname)) {
    break processed;
  }
  // ...
}

The purpose of the label is for control flow. I chose the name “processed” so that the break processed statement would be expressive to future maintaners. The PR feedback comment it received was:

this is really cool, but I am instinctively fearful of it

Look, I totally get it. Labels and GOTO have maintaned a lengthy and contentious co-dependent relationship. And we’ve all been burned before. It is completely reasonable to ask; “Is Label really ready to move on?”

Yes, Label is ready. Given the right opportunity, Label can shine. But we’ve all experienced trauma, so please take it slow … and be gentle.

Well, I’m Not So Sure …

I can understand that. What alternatives might you propose?

Why don’t you refactor it into smaller Functions?

That is a tried-and-true pragmatic approach.

However I would contend that, of the three phases, the decoding & return-value parts are drop-dead simple. Only the progressive logic is of real “value”, and it could be factored out – much like I did for some top-level consts – but you’ll just end up spreading the end-to-end logic around into two different places.

If the decoding phase were to get more complicated, that might be an incentive to refactor. Whereas the return-value phase is built to match the complexity of what the progressive logic can derive, so they’re already coupled.

I would say that “now is not the time”.

Why don’t you use a try { } finally { } statement?

I agree, that is a viable alternative.

But then you end up using a Exception-handling construct to implement the desired control flow, which I would suggest is a worse shoe-horning of the language. Whereas with the labeled statement,

  • there’s no contrived Exception-but-not-really implementation; in the end, we want something equally as expressive as the “processed” label
  • there’s no extra catch(err) { } or finally { } syntactic sugar involved; it’s just a label in front of a block
  • given the two points above, a Reviewer is likely to have opinions on your alternate solution, too
  • and, to drive home the point – the labeled statement approach will result in fewer lines of code

Why don’t you replace it all with early returns?

Because that’ll be (a) more lines of code or (b) more complicated code in the same “number of lines”. And, without TypeScript (or a similar formalization) to guide you, the structs of those invididual returns must all be kept in sync.

The decoding step does have its own return, and that makes for a grand total of two. I believe it reads best that way, for purposes of maintainability.

It’s like a switch { case } without breaks !

No. It really isn’t.

For the love of god, refactor this !!!1!

Wow.

Okay. I think I may have overstepped some boundaries here, and for that, I’m sorry. Maybe it would be better to discuss this again at some later time?

Yeah, probably. I could really use some coffee.

Sounds like a good plan :+1: :coffee: .

While you do that, I’ll sum up.

In Summary

The intent of this post was to demonstrate how a label can provide effective and expressive control flow in modern JavaScript code (for example). It also attempts, in some small way, to diminish the stigma associated with labels as a whole.

Time and time again, GOTO has shown itself to be a narcissistic blowhard that ruins everything it touches. Is it any surprise that labels have gotten a bad rap by association?

Perhaps we shouldn’t judge a language feature, even by the admittedly awful company that it keeps.

A Parting Thought

Here’s a neat little tick for dealing with instanbul / nyc code coverage:

/* istanbul ignore next */
_uncovered: {

  // ...

}