teaching machines

CS 330 Lecture 9 – Types

Dear students,

Today we begin our exploration of programming language concepts, rather than the tools (regex) that we’ll later use for interpreting programming languages. In particular, we start off our discussion with C. I used to talk about assembly first, because no programming language should be evaluated outside the context of history. All that humans make is shaped by what exists at the time of a thing’s making. We can summarize what led up to C as follows:

  1. Programming by circuit building. We plugged cables between hardware that only knew how to do one thing.
  2. Programming by flipping switches. Thanks to switching technology like transistors, complex circuits could be built once and left intact, with the particular pathway that electrons took between input into output programmed via hardware switches.
  3. Programming by machine code. Instead of hardware switches, the switches could be specified as a stored program, either on punch cards or a stored program.
  4. Programming by assembly. A human-readable veneer was laid over the processor’s binary instruction set, introducing the possibility for a single assembly language to be used for multiple different machine codes.
  5. Programming by Fortran, Cobol, LISP, and many others.

What did C and its above-assembly siblings bring to programming? I can think of a few things:

  • procedural abstraction
  • flow control
  • readability
  • standard libraries
  • register management
  • types

Let’s focus on types today. What sort of types does C provide? These go in the first draft of my list:

  • integer
  • real
  • character
  • array
  • struct
  • pointer
  • boolean (as of C99)

What types does C not provide?

  • Strings. Null-terminated strings are a convention of the standard library that lives outside the type system. Case in point, the compiler doesn’t check that a string is still a string after I operate on it.
  • Enums. C’s enum is really just a shortcut for defining a bunch of integer constants.
  • Data structures. There’s no linked list or hashtable or stack built in to the language proper.
  • Maybe types, which allow a value to be represented as undefined, though pointers can use NULL for this.
  • Tuples, which are a composite type much like structs. They collect a fixed number of fields together under one umbrella, and the fields can be of different types. Unlike a struct, however, the fields are not named. We refer to them by their position.

Does C allow the user to define new types? Yes, through struct. One can also use typedef to create a shorter name for an existing type (or a longer name, if that’s your thing), but typedef doesn’t really introduce a new type.

Let’s write some code to back up my claim that C doesn’t really have enums—at least not typesafe ones. Let’s write a program to evaluate a hand of Blackjack.

Here’s your TODO list for next time:

  • Read What to know before debating type systems. On a quarter sheet, write down 2-3 questions or observations inspired by your reading. Consider sharing your thoughts on type systems in the languages you’ve used.

See you then!

Sincerely,

P.S. It’s Haiku Friday!

“You’re one of a kind.”
That’s how he wooed 2. And 3.
And 4, 5, and 6.

dollar.rb

#!/usr/bin/env ruby

foo = 17
$foo = 17

def slar
  # puts foo
  puts $foo
end

slar

blackjack.c

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

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

int score(card_t *hand, int ncards) {
  int score = 0;
  int naces = 0;

  // Sum up all the non-aces, and count the aces.
  for (int i = 0; i < ncards; ++i) {
    if (hand[i] == ACE) {
      ++naces;
    } else {
      score += hand[i];
    }
  }

  // Figure out how to count the aces.
  if (naces > 0) {
    int max = 11 + naces - 1; // no more than one can be worth 11
    int min = naces;
    if (score + max <= 21) {
      score += max;
    } else {
      score += min;
    }

    /* Another way:

      // Count all aces as ones.
      score += naces;

      // Could one of them have been counted as 11 (1 + 10) instead?
      if (score + 10 <= 21) {
        score += 10;
      }

     */
  }

  return score;
}

int main(int argc, char **argv) {
  /* card_t hand[] = {ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE, ACE}; */
  card_t hand[] = {21};
  printf("Score: %d\n", score(hand, 1));
  return 0;
}

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *