CSC 347 - Concepts of Programming Languages

Static and Dynamic Types

Instructor: Stefan Mitsch

Learning Objectives

How should we support programmers in interpreting memory content correctly?
How should we support programmers in applying operations correctly?

  • Understand the role of types
  • Understand the difference between static and dynamic types

Programming Without Types

What is difficult about the code below?
How can we improve the language to better support programmers?

void* getNext(void* x) {
  return *(x+4);
}
void* n = malloc(12); 
*n = 42; 
*(n+4) = NULL;
void* nn = getNext(n);
Solution
typedef struct Node { int value; Node* next; } Node;
Node* getNext (Node* x) {
  return x->next;  
}
Node* n = malloc(sizeof(Node)); 
n->value = 42; 
n->next = NULL;
Node* nn = getNext(n);

Types

  • Types define offsets
    typedef struct Node { int value; Node* next; } Node;
    Node* getNext (Node* x) {
      return x->next;  
    }
    
  • Types determine valid operations
    class Main () {
      public static void main (String[] args) {
        System.out.println( 1 - 2 );
        System.out.println( "dog" - "cat" );
      }
    }
    

Type Enforcement

  • Statically, track types with compiler
    • Compile time
    • Early
  • Dynamically, store type with object
    • Run time
    • Late

Dynamic Type Checking in Scheme

  • Dynamic type checking detects a failure

  • How do we know Scheme is dynamic?

    #;> (- 5 "hello")
    Error in -: expected type number, got '"hello"'.
    
  • Type checker invoked before execution starts?

Dynamic Type Checking in Scheme

#;> (define (f) (- 5 "hello"))
#;> (f)
Error in -: expected type number, got '"hello"'.
  • Defer computation to function body
  • Failure is when f runs
  • Conclusion: no type checking before execution

Static Type Checking in Java

class Typing01 {
  public static void main (String[] args) {
    int a = 5;
    String b = "hello";
    System.out.println ("Result = " + (a - b));
  }
}

javac rejects code with (5 - "hello")

$ javac Typing01.java
Typing01.java:5: error: bad operand types for binary operator '-'
    System.out.println ("Result = " + (a - b));
                                        ^
  first type:  int
  second type: String

Dynamic Type Checking in Java

  • We can make the error dynamic by casting
class Typing01 {
  public static void main (String[] args) {
    int a = 5;
    String b = "hello";
    System.out.println ("Result = " + (a - (int)(Object)b));
  }
}
$ java Typing01
ClassCastException: class String cannot be cast to class Integer
	at Typing01.main(Typing01.java:5)

Variables in Static Languages

  • In static languages, variables also have types
class Typing06 {
  public static void main (String[] args) {
    int a = 5;
    a = "hello";
  }
}
$ javac Typing06.java 
Typing06.java:4: error: incompatible types: String cannot be converted to int
    a = "hello";
        ^

Casting

  • We can convert any static error into a dynamic one: casting turns compile-time errors into runtime errors
class Typing06 {
  public static void main (String[] args) {
    int a = 5;
    a = (int)(Object)"hello";
  }
}
$ java Typing06      
ClassCastException: class String cannot be cast to class Integer
	at Typing06.main(Typing06.java:4)

Type Inference

  • Java infers the most precise type possible for a var
class Typing06 {
  public static void main (String[] args) {
    var a = 5;
    a = "hello";
  }
}
$ javac Typing06.java
Typing06.java:4: error: incompatible types: String cannot be converted to int
    a = "hello";
        ^

Variables in Dynamic Languages

  • Variables do not have types in dynamic languages
  • Only values have types
#;> (define (main)
       (define a 5)
       (set! a "hello")
       (display a)
    )
#;> (main)
"hello"

Tradeoffs

  • Dynamic
    • more flexible
    • usually conceptually simpler
    • faster compilation
    • easier runtime code generation/modification
  • Static
    • compile-time detection of errors
    • no unit tests for type checking
    • automatic documentation
    • faster runtime (dynamic checks, optimization)
    • less memory consumption at runtime

Static Type Checking

  • Static types are conservative
    int f (int i, String s) {
      return true ? i : s;
    }
    
  • Static types may use type inference
    var x = 1;
    

Summary

  • Static type checking
    • at compile time
    • variables have types, but can often be inferred
  • Dynamic type checking
    • at runtime
    • variables do not have types, data has types