Hacker News new | ask | show | jobs
by bdrool 3527 days ago
> That's part of a chapter of the book called Minimizing Control Structures.

Since the book is creative commons and freely available, I decided to download the book and have a look. Figure 8.1, the "automatic teller" example is just downright hilarious. The author presents the code and throws a challenge at the reader: "Easy to read? Tell me under what condition the user’s card gets eaten." Here's the code:

  IF card is valid DO
    IF card owner is valid DO
      IF request withdrawal DO
        IF authorization code is valid DO
          query for amount
          IF request <= current balance DO
            IF withdrawal <= available cash DO
              vend currency
              debit account
            ELSE
              message
              terminate session
          ELSE
            message
            terminate session
        ELSE
          message
          terminate session
      ELSE
        IF authorization code is valid DO
          query for amount
          accept envelope through hatch
          credit account
        ELSE
          message
          terminate session
    ELSE
      eat card
  ELSE
    message
  END
(hopefully no transcription errors from copying out of the PDF…)

Yes, it's easy. It gets eaten if the owner is not valid. Took one glance.

The thing that makes me laugh is that the example is contrived. This is the sort of thing code editors solve. Even though I could quickly glance at it and decipher the conditionals by eye, if I were working with this I'd still throw it into an editor that shows me code scope. That makes it trivial and removes any chance of error. This is a problem that has been solved.

I'm sure I will get a lot of responses saying I've missed the point, and yes I'm aware that I've dodged it, but the author acts like the problem of navigating nested conditionals is somehow impossible, which I think is ridiculous. Not only do lots people do it every day, not only are there tools that help us do so, but there's pretty much no way to exist in this world without depending on software that is written this way (ever looked at the source for GCC, to pick one example?) Not saying it's right, but it's clearly not a deadly problem.

3 comments

Just as taste is a subjective thing as is often hard to articulate... I think my biggest complaint about that code is that I had to read all of it to make sure there weren't other cases where the card gets eaten. And try to follow what was going on.

Taste-wise, an easy fix for this is to do early exits. Instead of nesting, you could easily do (I'm on mobile so no fancy formatting):

If card is not valid: return message

If user is not valid: eat card; return

Etc

Now that's my personal taste. It makes it way simpler to quickly skim and understand what's going on.

> Yes, it's easy. It gets eaten if the owner is not valid. Took one glance.

Nit-pick, but it seems that the card only gets eaten if the card is valid AND the owner is not valid. If the card isn't valid, the owner is never checked and the card isn't eaten.

Just the raw formatting of that could be improved, by cuddling up ELSE IF from separate lines.

Aren't there some END tokens missing? Let me put them in:

  IF card is valid DO
    IF card owner is valid DO
      IF request withdrawal DO
        IF authorization code is valid DO
          query for amount
          IF request <= current balance DO
            IF withdrawal <= available cash DO
              vend currency
              debit account
            ELSE
              message
              terminate session
            END
          ELSE
            message
            terminate session
          END
        ELSE
          message
          terminate session
        END
      ELSE
        IF authorization code is valid DO
          query for amount
          accept envelope through hatch
          credit account
        ELSE
          message
          terminate session
        END
    ELSE
      eat card
    END
  ELSE
    message
  END
Okay, now:

  IF card is valid DO
    IF card owner is valid DO
      IF request withdrawal DO
        IF authorization code is valid DO
          query for amount
          IF request <= current balance DO
            IF withdrawal <= available cash DO
              vend currency
              debit account
            ELSE
              message
              terminate session
            END
          ELSE
            message
            terminate session
          END
        ELSE
          message
          terminate session
        END
      ELSE IF authorization code is valid DO
        query for amount
        accept envelope through hatch
        credit account
      ELSE
        message
        terminate session
      END
    ELSE
      eat card
    END
  ELSE
    message
  END
Okay, just one ELSE IF; not much opportunity for that.
On that topic, I did a somewhat weird thing in C yesterday. I took code like this:

  for (;;) {
    /* original big loop */
  }
and turned it into this:

  if (compatibility_with_old_version) for(;;) {
    /* original big loop: same indentation level! */
  } else for (;;) {
    /* rewritten new loop */
  }
 
I.e.

  if (...) for (...) {

  } else for (...) {

  }
Works for me.