CSC447

Concepts of Programming Languages

Dynamic/Static Types

Instructor: James Riely

Types

  • Types define offsets
    
    struct Node { int head; struct Node* tail; };
    struct Node* getNext (struct Node* x) {
      return x->tail;  
    }
                  
  • 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

Types in C

  • C does not enforce types. Why have them?
  • Only to compute offsets

struct Node { int head; struct Node* tail; };
struct Node* getNext (struct Node* x) {
  return x->tail;
}
          

Example: Lox / Dynamic

  • Dynamic type checking detects a failure
  • How do we know this is dynamic?
  • Type checker invoked before execution starts?

lox11> print 5 - "hello";
Operands must be numbers.
          

Example: Lox / Dynamic

  • Defer computation to function body
  • Failure is when f runs
  • Conclusion: no type checking before execution

lox11> fun f () { print 5 - "hello"; }
lox11> f();
Operands must be numbers.
          

Java is Static

  • 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
          

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

Java is Dynamic

  • We can make the error dynamic by casting

$ java Typing01
ClassCastException: class String cannot be cast to class Integer
	at Typing01.main(Typing01.java:5)
          

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

Variables in Static Languages

  • In static languages, variables also have types

$ javac Typing06.java 
Typing06.java:4: error: incompatible types: String cannot be converted to int
    a = "hello";
        ^
          

class Typing06 {
  public static void main (String[] args) {
    int a = 5;
    a = "hello";
  }
}
          

Static to Dynamic

  • We can convert any static error into a dynamic one

$ java Typing06      
ClassCastException: class String cannot be cast to class Integer
	at Typing06.main(Typing06.java:4)
          

class Typing06 {
  public static void main (String[] args) {
    int a = 5;
    a = (int)(Object)"hello";
  }
}
          

Java var

  • Java infers the most precise type possible for a var

$ javac Typing06.java
Typing06.java:4: error: incompatible types: String cannot be converted to int
    a = "hello";
        ^
          

class Typing06 {
  public static void main (String[] args) {
    var a = 5;
    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"
          

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;
                  
  • Static types may be separate from the program, as in Flow

Tradeoffs

  • Dynamic:
    • flexible, conceptually simpler
    • faster compilation
    • easier runtime code generation/modification
  • Static:
    • compile-time detection of errors, fewer unit tests
    • documentation
    • smaller and faster runtime (fewer dynamic checks, more optimization)
    • advanced idioms:
      • dependency injection in typescript or angular
      • implicits in Scala, typeclasses in Haskell
      • borrow checking and data-race freedom in Rust
      • proofs of correctness in Coq and Agda