Programming Languages: Chapter 7: Strong Typing and Type Inference



Strong typing

  • definitions vary
  • a simple, but incomplete definition is: ``a strongly-typed programming language is one in which each name in a program has a single type associated with it, and that type can be determined at compile time'' [COPL6] (i.e., by looking at the program) not running it; this means that all types are bound at compile-time (i.e., statically bound)
  • another, perhaps more general and all inclusive, definition is: a strongly-typed programming language is one in which ``type errors are always detected'' [COPL9]; means we must be able to determine the type of everything just by looking at the program, and not by running it
  • FORTRAN, C, and C++ are not strongly typed
    • languages with coercion (e.g., FORTRAN, C, and C++ are weakly typed)
    • C and C++ use coercion, int x = 3.4;
    • C and C++ support unions which are not type checked
  • Ada is almost strongly-typed; the programmer can suspend type checking
  • C# and Java (even though they are based on C/C++) are strongly typed but have casting
  • ML and Haskell are strongly-typed
  • in safety, Haskell is the Java of functional programming languages
  • why use a strongly-typed programming language? reliability and safety
  • why use a weakly-typed programming language? flexibility and efficiency
  • LISP is said to be a typeless language

  • ML comes with irremovable training wheels
      3-4; (* works *)
      
      (* 3-4.4; doesn't work *)
      
      (* no coercion in ML, why? *)
      
      real(3)-4.4; (* this is a type cast *)
      
      open Real;
      Real.< (2.9, 3.0); (* Real is called a structure; open a class in OO *)
      
      false andalso (1 / 0); (* doesn't work, why? *)
      false andalso (1 div 0); (* still doesn't work, but not because of a divide by 0 *)
      


Type inference in Haskell

    ``In Haskell every expression must have a type, which is calculated prior to evaluating the expression by a process called type inference. The key to this process is a typing rule for function application, which states that if f is a function that maps arguments of type A to results of type B, and e is an expression type A, then the application f e has type B:

         f :: AB       e :: A

                 f e :: B

    For example, the typing not False :: Bool can be inferred from this rule using the fact that not :: Bool → Bool and False :: Bool'' [PIH].


Type inference in ML

  • ML and Haskell use type inference to help relieve the programmer from associating a type with every name in a program
  • there is a built-in type inference engine (algorithm) to determine the type of a name based on the context (see inference rules in handout)
  • ML and Haskell do type inference
  • in what places in a program can we attached a type to a name? primarily:
    • variables
    • function parameters
    • return types
  • first let us see how to associate types with names (which to this point we have not done)
      - fun square (n) = n*n;
      val square = fn : int -> int
      -
      - fun square (n: real) = n*n;
      val square = fn : real -> real
      -
      - fun square (n): real = n*n;
      val square = fn : real -> real
      -
      - fun square (n: real): real = n*n;
      val square = fn : real -> real
      
  • key point: type inference gives us strong typing without explicit type declarations
  • for more information, see [EMLP] p. 63


How ML deduces types: examples

    (* the 0 returned in the first case
    causes ML to use the type
    "int list -> int" for summing *)
    fun summing (nil) = 0
    |   summing (x::xs) = x + summing (xs);
    
    fun f1 (a, b) = if (a < b) then 3.0 else 2.0;
    (* val f1 = fn : int * int -> real *)
    
    (*
    fun f2 (a, b) = if (a < b) then 3.0 else 2;
    stdIn:7.17-7.43 Error: types of if branches do not agree [literal]
      then branch: real
      else branch: int
      in expression:
        if a < b then 3.0 else 2
    *)
    
    fun f3 (a, b) = if (a + 0.0) < b then 1 else 2;
    (* val f1 = fn : real * real -> int *)
    
    See [EMLP] § 3.2.4 (pp. 63-64) for more information.


Overloading

    contrast square function in Haskell with that in ML
    square n = n*n
    
    Main> :type square
    square :: Num a => a -> a
    -- the type of square is a 'qualified type'
    -- and Num is a 'type class'
    


References

    [COPL6] R.W. Sebesta. Concepts of Programming Languages. Addison-Wesley, Boston, MA, Sixth edition, 2003.
    [COPL9] R.W. Sebesta. Concepts of Programming Languages. Addison-Wesley, Boston, MA, Ninth edition, 2010.
    [EMLP] J.D. Ullman. Elements of ML Programming. Prentice Hall, Upper Saddle River, NJ, Second edition, 1997.
    [PIH] G. Hutton. Programming in Haskell. Cambridge University Press, Cambridge, 2007.

Return Home