teaching machines

CS 330: Lecture 13 – Types: Safe vs. Unsafe

March 2, 2018 by . Filed under cs330, lectures, spring 2018.

Dear students,

While you’re waiting for class to start, here’s a little exercise for you to discuss with your neighbor:

How would you write an algorithm for computing the score of a hand of Blackjack? Face cards are worth 10, aces are worth 1 or 11, and everything else is worth its rank. Sum up the hand to get as close to 21 as possible without exceeding it.

We’ve talked about static vs. dynamic type systems and explicit vs. implicit. In case it hasn’t been made clear, types are a very big deal. They have a significant impact on the compile and runtime performance, and they form a major part of software correctness.

On to the next dimension of type systems: safe vs. unsafe. I used to call this dimension strong vs. weak, but these terms have definitions that are O(n). Our definition of unsafe is this: a type system with an on/off switch. If a value of one type can treated as being of another type, without first undergoing some language-sponsored conversion therapy, that’s an unsafe, subvertible type system. A safe type system, on the other hand, means the type system cannot be turned off. By these definitions, there are very few unsafe languages. C and C++ are for sure.

A safe type system keeps its taste buds operating at all times. An unsafe type system recognizes that sometimes you need to swallow wretched things, and it’d be better to turn them off.

Let’s see an example of subverting types in C.

enums in C are one example of unsafe typing. We’ll see that the type checking of enums is effectively turned off. We’ll implement a little algorithm for calculating a hand of Blackjack.

Here’s your TODO list for next time:

See you then!

Sincerely,

P.S. It’s time for a haiku!

I didn’t eat meat
Before this desert island
Now, can’t get enough

P.P.S. Here’s the code we wrote together:

blackjack.c

#include <stdio.h>
#include <stdlib.h>

typedef enum {
  ACE,
  TWO,
  THREE,
  FOUR,
  FIVE,
  SIX,
  SEVEN,
  EIGHT,
  NINE,
  TEN,
  JACK = 10,
  QUEEN = 10,
  KING = 10
} card_t;

unsigned int score(card_t *cards, unsigned int n) {
  unsigned int total = 0;
  unsigned int naces = 0;
  for (unsigned int i = 0; i < n; ++i) {
    if (cards[i] != ACE) {
      total += cards[i];
    } else {
      ++naces;
    }
  }

  if (naces == 0) {
    return total;
  } else if (total + 11 + (naces - 1) <= 21) {
    return total + 11 + (naces - 1);
  } else {
    return total + naces;
  }
}

unsigned int score2(card_t *cards, unsigned int n) {
  unsigned int total = 0;
  unsigned int naces = 0;

  for (unsigned int i = 0; i < n; ++i) {
    total += cards[i];
    if (cards[i] == ACE) {
      ++naces;
    }
  }

  if (naces > 0 && total + 10 <= 21) {
    total += 10;
  }

  return total;
}

int main(int argc, char **argv) {
  printf("ACE: %d\n", ACE);
  printf("TWO: %d\n", TWO);
  printf("THREE: %d\n", THREE);
  printf("FIVE: %d\n", FIVE);
  printf("KING: %d\n", KING);

  /* card_t cards[] = { */
    /* 21 */
    /* TWO, */
    /* TWO, */
    /* TWO, */
    /* THREE, */
    /* THREE, */
    /* THREE, */
    /* ACE, */
    /* ACE, */
    /* ACE, */
    /* ACE, */
    /* TWO */

  /* }; */

  /* unsigned int wholesome = score(cards, 1); */
  /* printf("score: %d\n", wholesome); */

  return 0;
}