Type checking I
Lecture 7

Table of Contents


Questions about the last class?


What is an example of a programming language that lacks a type system, but nevertheless are still safe from bad behavior (according to Cardelli's definition) at runtime?

Quiz Discussion

Why do type checking?

Prevent "unsafe" behavior

  • Add one to a struct
  • Array out of bounds access
  • Null pointer dereference
  • Arithmetic overflow

prevent programming errors

static (compile-time) vs. dynamic (run-time, cardelli calls this checking, reserving types for static definitions)

strict vs. weak

design considerations (halting problem)

What is a "type" in a typed language?

Typed languages restrict what values a symbol will hold

  • A set of values
  • and operations on those values
  • Examples
    • int: the set of integers (1, 53, -2, etc.), arithmetic operations
    • bool: { true, false } and logical operations (and, or, not)
    • string: { "hello", "world", … } and concatenation

Type checking ensures restrictions aren't violated

Untyped languages

  • No restriction on range of values
    • Every symbol can have every value
  • What about "bad behavior" in these languages?

Safe vs. unsafe behavior

Cardelli distinguishes between trapped vs. untrapped

  • Trapped
    • Terminated by the machine, e.g., null-pointer dereference, divide-by-zero
  • Untrapped
    • Silent errors (program continues running), e.g., writing past array bounds, adding one to a struct reference
  • Safe languages prevent untrapped (and some trapped) errors

Why focus on untrapped?

Trapped caught at runtime

Untrapped fail silently

Untrapped (and some trapped too) may be infeasible or impossible to determine without execution (related to the halting problem)

When to check safety?

Compile-time vs. run-time

  • Compile-time (static) checking: C, Rust, Java, etc.
  • Run-time (dynamic) checking: Python, Lisp, Java(?)

Cardelli distinguishes between types and checking, e.g., languages like lisp enforce safety albeit at runtime, but is checking is not type checking, since lisp is untyped.

Effectively, "typing" means the language (i.e., syntax and semantics) defines type rules, not only that behaviors that types prevent happen to be checked during execution.

Practical type checking

  • Forbidden errors: all untrapped errors and some trapped
  • Good behavior: a program has no forbidden errors

This also depends on what types have been included in the language. For example, you can implement subclassing in C, but C's type system will not enforce it.

How much checking to perform?

  • Strongly-checked: all legal programs have good behavior
  • Weakly-checked: some programs violate safety

What are some examples of strongly- and weakly-checked languages?

  • In weakly-checked languages, what are some examples of violative programs that don't get rejected?

Type systems restrict what input programs are part of the language (similarly to how grammars restrict the space of input programs). A legal program is one that is part of the language.

If safety is so important, why have weak checking at all?

Examples of languages

  Typed Untyped
Safe ML, Java LISP
Unsafe C Assembly

Note the distinction between having a type system vs. whether the language checks type safety.

Demo: Python vs. C

Dynamic checking:


x = "degrees"

x = 1.7 + " degrees"
y = 1.7 * 2
print y

Static checking:

#include <stdio.h>

int main() {
  printf("STARTED RUNNING\n");

  double temp = (double)2;
  int y = 1.7 * temp;
  /* int y = ((void *)1.7) * (float)((void *)2); */

  float yf = 1.7 * 2;

  printf("%x\n", y);
  printf("%f\n", yf);

  return 0;

Unsafe program allowed by weakly-checked language:

#include <stdio.h>

int main() {
  printf("STARTED RUNNING\n");

  float x = 1.7;

  float *p = &x;
  int *ip = (int *)p;

  printf("%d\n", *ip);  

  return 0;

Author: Paul Gazzillo

Created: 2023-04-13 Thu 14:59