CP2003 Lecture Notes - Type Inferencing and Coercion

These lecture notes are based on chapter 7 in ``Programming Language Concepts and Paradigms'' by David Watt and the Java Language Tutorial from Sun.

Type Inference

Are type declarations really needed? Remember the factorial function. Let's write the factorial function in Pascal, but without typing variables and try to figure out what type it returns.

   { factorial function }
   function factorial ( x : ? ) : ?;
     begin
       if x = 0 then factorial := 1;
       else factorial := x * factorial(x - 1);
     end;
We can infer that factorial returns an integer value because it returns a 1, and we can infer that x is an integer because we compare it to an integer. We could then check all the calls to factorial to determine if they passed an integer.

But it is not always possible to infer monomorphic types.

   { identity function }
   function identity ( input : ? ) : ?;
     begin
       identity := input;
     end;
What type of value is returned? A polymorphic type (i.e., any type).

Type inference is typically done to improve the efficiency of ``typeless'' languages. For example, the Icon compiler does type inference.

   # Icon example
   letter := 'c';      # we know that letter is a char
   letter2 := letter;  # can generate code to do a byte move since a char
                       # is byte sized.

Type Coercion

Often it is convenient for a programmer to mix different types in an expression (often an arithmetic expression). Most languages recognise and implicitly coerce values to the appropriate types when it makes sense.

   int x;
   double y;
   char ch;

   x = 20;
   y = (x * 4); /* result of x * 4 is coerced to a float */
                /* it makes sense to convert an int to a float */
   ch = y;      /* not coerced, error */
Coercion is often from narrower to wider types (widening), for instance from integers to reals (can think of integers as a subset of reals). But we could coerce from reals to integers (truncation).

In some languages, we can explicitly coerce between types that are not normally coerced via casts.

   double y;
   char ch;
   
   y = 1.0;
   ch = (char) y;  /* what ends up in ch? */