Support Statement: Reducing Late Calls, CallByName/dynamic

Statements using CallByName or referencing members through the special type dynamic are called "late calls".  They indicate a problem with type inference.  In some cases, this can reduce the accuracy of the upgraded code. This can happen for statements of the form:


objexp.member

where 
objexp is some variable or expression
member is some API element that is expected to be a valid member of the type of object returned by the expression


Most often, late calls happen when the tool does not find the type of 'objexp' declaring the 'member' referenced.  The timing of when types are determined also plays a role.  In addition, using a single weakly typed variable with a variety of different types often creates ambiguities that result in late calls.  
 
There are many scripting commands improving type inference and reducing late calls:
  • adding reference, registry/libname commands to ensure the correct COM interface description files are loaded
  • adding registry/progid to assist with resolution of ProgIDs in CreateObject statements
  • adding compile/fix to change the declaration of object by editing source code
  • adding registry/fixtype command to set the type of a set of like-named variables
  • adding refactor/fixtype command to set the type of a specific symbol of like-named variables
  • adding refactor/overload to allow flexible strongly typed method arguments
  • editing the IDF (or providing a mig.IDF file) to specify stronger types
  • adding a refactor/callbyname statement (see the gmPL guide)
  • using Select TypeInference=on
  • adding refactor/migrate commands to the translation script to change types
     
These techniques and additional information are discussed further in this documentation.

Interfaces and Generics

The first strategy should be to using a single concrete class rather than a weak type. Generally speaking the tool attempts to do this inferring strong types to replace Variant and Object based on usage or other metadata provided.  Occurrences of dynamic cast indicate places where type inference was not possible, occurred too late, or there is an object.member mismatch -- typically lack of information or deliberate ambiguity.  As discussed above, it is possible to provide various  "Type Inference Hints" based on an analysis of the code or prior knowledge of the system.  The use of "firm types" such as interfaces and generics comes into play when using a single strong type is not possible.  In some cases it may be necessary to introduce new interfaces and custom types by creating and loading custom IDF files to define them.