Coyote's Guide to IDL Programming

Compiling IDL Functions

QUESTION: IDL will occasionally confuse one of my function calls as a variable reference. This is true even if I have compiled the function previously. The problem seems to go away if I compile the function a second time. What is going on here?

ANSWER: This is almost always the result of the way IDL procedures and functions are ordered in a file. IDL has a rule that a function must be compiled before it is called or used. But understanding exactly what this means can be confusing. Here is a short example that illustrates the problem. The file will be named main.pro.

   PRO Utility
      value = MyFunction(5)
   END

   FUNCTION MyFunction, number
      RETURN, Randomu(seed, number)
   END

   PRO Main
      Utility
      Print, MyFunction(3)
   END

If I enter IDL and just type "Main", I get an error:

IDL> Main
% Compiled module: MAIN.
% Variable is undefined: MYFUNCTION.
% Execution halted at:  UTILITY             2 C:\RSI\IDL52\DAVID\main.pro
%                       MAIN               10 C:\RSI\IDL52\DAVID\main.pro
%                       $MAIN$                 

This happens even if I compile the program immediately upon entering IDL:

IDL> .Compile main
% Compiled module: UTILITY.
% Compiled module: MYFUNCTION.
% Compiled module: MAIN.
IDL> Main
% Variable is undefined: MYFUNCTION.
% Execution halted at:  UTILITY             2 C:\RSI\IDL52\DAVID\main.pro
%                       MAIN               10 C:\RSI\IDL52\DAVID\main.pro
%                       $MAIN$                 

Although the problem goes away if I compile it again:

IDL> RetAll
IDL> .Compile main
% Compiled module: UTILITY.
% Compiled module: MYFUNCTION.
% Procedure was compiled while active: MAIN. Returning.
% Compiled module: MAIN.
IDL> Main
     0.678165     0.424276     0.444070

What is going on here is that when the first program module, Utility, is compiled there is an unresolved reference to the function MyFunction. Since at that moment this function has not been compiled, IDL puts the reference on its internal variable list instead of its internal function list for that module. Thus, the error occurs when the program is run. At the time the Utility module is called the second time, the function has been compiled, so the internal reference is made to a function and not to a variable and the program works.

The problem is easily solved by moving the function ahead of the Utility procedure in the file:

   FUNCTION MyFunction, number
      RETURN, Randomu(seed, number)
   END

    PRO Utility
      value = MyFunction(5)
   END

  PRO Main
      Utility
      Print, MyFunction(3)
   END

Now, when I enter IDL and call it by name I get this:

IDL> Main
% Compiled module: MAIN.
     0.383502     0.653919    0.0668422

Normally, this kind of problem is either solved by putting all the function utility modules in front of the procedure utility modules in the file. (The last module in the file is, of course, the command module (i.e, the module with the same name as the file and the one with the name of the "command" you are trying to create) and should always be last whether it is a procedure or function. Or, if a function is going to be called by more than one module, as is the case here, I might take that function out of this file and put it in a file of its own, with the same name as the function. Then it can be found normally by any program module that needs it.

Another solution, which I consider to be the solution of last resort, is to use the Forward_Function statement in IDL to make sure IDL considers any unresolved reference to the function to be a function reference and not a variable reference. I've never yet had to resort to this in my programs, but I guess I can envision code so complicated that it might be necessary.

   Forward_Function MyFunction

   PRO Utility
      value = MyFunction(5)
   END

   FUNCTION MyFunction, number
      RETURN, Randomu(seed, number)
   END

   PRO Main
      Utility
      Print, MyFunction(3)
   END

Now if I enter IDL and just type "Main", I get the correct response:

IDL> Main
% Compiled module: MAIN.
     0.383502     0.653919    0.0668422

[Return to IDL Programming Tips]