Coyote's Guide to IDL Programming

File Naming Conventions

QUESTION: What one thing can I do to improve my IDL code without having to, like, learn anything new?

ANSWER: You can name your programs properly. :-)

We write IDL procedures and functions for one and only one purpose: we wish to make a new command in IDL. That is, we are gathering previously-written IDL commands together in a new procedure or function for the purpose of creating a new command that we can use (hopefully) to do something useful. The name of the procedure or function we write to do this I call the command name. The command name of the function below, for example, is Add_M_Up.

FUNCTION Add_M_Up, val_1, val_2
   retValue = val_1 + val_2
   RETURN, retValue
END

If you wish not to have to manually compile every IDL command before you use it (and if you have to think about this for even a fraction of a second, let me assure you, you do not want to manually compile your IDL commands, not even once!), you will give the file that contains this function the same command name as the function. That is, you will name the file "add_m_up.pro".

Notice the filename is in lowercase characters and there are no spaces or other funny characters in the filename. This is because you want your boss to be able to run your program on her machine without cursing you every time she tries. If you work on a Macintosh computer and you are used to giving your files grandious mixed-case names with lots of easy-on-the-eye spacing, you are going to have to realize that 95 percent of the world can't afford that kind of luxury. Someday, someone, somewhere is going to want to run your program on one of those other computers, and he will be disappointed with you if you don't do what I am telling you to do. So, lowercase spelling, no spaces, the name of the file the same as the name of the command you are trying to build.

If you do nothing more than what I have told you so far, you will eliminate 90 percent of the problems you are having with file names.

But, David (I can hear you saying), does this mean that I can only have one procedure or function in a file!? No, it doesn't mean that. But I do mean that you have to give some thought about the other procedures or functions in your file. For example, you have to answer this question. "What is the purpose of these other procedures and functions in the file?"

If you tell me they are commands, in just the way Add_M_Up is a command. That is to say, they are meant to be used at the IDL command line, just like you plan to use Add_M_Up, then I would tell you to get them out of the add_m_up.pro file and put them in their own files, named with their own command names.

If you tell me the other procedures and functions in the file are meant to be used only by the Add_M_Up command, then I will tell you to leave 'em alone. You can have as many utility routines in a file as you like if you follow a few simple rules.

Rules for Naming and Placing Multiple Procedures and Functions in a File

Rule 1: All modules except the command module (which has the same name as the file itself) should be utility routines for the command module. Any procedure or function that gets too big for its britches and aspires to be a command module of its own should be removed from the file and placed in a file of its own.

Rule 2: The command module (which has the same name as the file itself) should be the last module in the file. All utility routines should be placed in front (toward the top of the file) of it.

Rule 3: The names of the utility routines should start with the command module name. Although not strictly required by IDL, you will find yourself in a great deal of trouble, sooner or later, if you give your utility modules arbitrary names. In other words, don't give a utility routine a name like Quit. Give it a name like Add_M_Up_Quit.

Here are the reasons for the rules. Suppose the values we passed to Add_M_Up weren't the values we wanted to add, but were indices into a look-up table. We might want to write a Look_M_Up function to look up the proper values. This function would clearly be a utility routine for the Add_M_Up function. Suppose we wrote the two functions and put them into a file like this. We will name the file add_m_up.pro.

FUNCTION Add_M_Up, val_1, val_2
   retValue = Look_M_Up(val_1) + Look_M_Up(val_2)
   RETURN, retValue
END

FUNCTION Look_M_Up, index
   index = 0 > index < 3
   table = [6, 3, 8, 11, 15]
   RETURN, table[index]
END

Now, suppose we start IDL up and type this command.

IDL> Print, Add_M_Up( 3, 1 )
   % Compiled module: ADD_M_UP.
   % Variable is undefined: LOOK_M_UP.
   % Execution halted at: ADD_M_UP            2 C:\IDL\DAVID\add_m_up.pro

IDL is not familiar with the command Add_M_Up (it hasn't been previously compiled and it is not a built-in system command) so it uses its rules for automatically searching for and compiling IDL commands. It begins to look for a file with the same name as the command. In other words, it looks for a file name add_m_up.pro in its search path (given by !Path). By default, IDL looks for file names spelled with lowercase characters.

We have written this file and placed it in a directory on IDL's path, so, of course, IDL finds the file. The next rule is that it compiles the procedures and functions in this file in the order in which they are defined in the file (top to bottom), until it finds a procedure or function having the same name as the file. If it finds such a program module, it compiles the module and immediately stops compiling the file and runs the module.

In our case, the IDL compiles the first module (Add_M_Up) and then, since this module has the same name as the file, stops compiling and runs Add_M_Up. The module Look_M_Up does not get compiled. But, of course, when IDL runs Add_M_Up it immediately runs into another command it doesn't recognize: the command Look_M_Up. It starts the process again. Only this time IDL can't find a file with the name look_m_up.pro (it doesn't exist), and--exhausting all possibilities--issues an error. Of course, in this case IDL assumes Look_M_Up is a variable, since it couldn't find a function!

We could solve the problem (possibly) by manually compiling the file, like this, but look what happens.

IDL> .compile add_m_up
   % Procedure was compiled while active: ADD_M_UP. Returning.
   % Compiled module: ADD_M_UP.
   % Compiled module: LOOK_M_UP.
IDL> Print, Add_M_Up( 3, 1 )
   % Variable is undefined: LOOK_M_UP.
   % Execution halted at: ADD_M_UP            2 C:\IDL\DAVID\add_m_up.pro 

Aaahhh. IDL has it in its head that Look_M_Up is a variable now and there will be no reasoning with it. :-(

But look what happens if we put the Look_M_Up module where it belongs, like this.

FUNCTION Look_M_Up, index
   index = 0 > index < 3
   table = [6, 3, 8, 11, 15]
   RETURN, table[index]
END

FUNCTION Add_M_Up, val_1, val_2
   retValue = Look_M_Up(val_1) + Look_M_Up(val_2)
   RETURN, retValue
END

Starting fresh.

IDL> .reset
IDL> Print, Add_M_Up( 3, 1 )
   % Compiled module: LOOK_M_UP.
   % Compiled module: ADD_M_UP.
   14

Perfect. Now the Look_M_Up module gets compiled ahead of the Add_M_Up module that uses it. IDL doesn't get confused about what is a function and what is a variable. And, best of all, we don't have to worry about compiling anything. It is all done for us.

But what happens if we build a Subtract_M function that uses its own Look_M_Up module that is different from the module we built for Add_M_Up? If we the run the Subtract_M command first and immediately use it, then no problem. It's local Look_M_Up module works perfectly. But what happens if we run the Add_M_Up command next, then go back and run the Subtract_M command?

When IDL is looking to run a command the first place it looks for the command is in its memory where compiled modules live. It has a Look_M_Up module compiled there, but it is the one that belongs to Add_M_Up, not the one that belongs to Subtract_M. So when we run Subtract_M, it calls the wrong Look_M_Up module! We are running into this problem because we didn't give our utility routine a unique name, we gave it a generic name. And this is going to be a hard problem to debug, because it is going to fail intermitently. It will depend upon whether or not we run Add_M_Up after we run Subtract_M. Believe me, you don't want these kinds of problems.

This problem can be solved by writing our add_m_up.pro file like this and giving our Look_M_Up module a unique name by using the command name as a preface.

FUNCTION Add_M_Up_Look_M_Up, index
   index = 0 > index < 3
   table = [6, 3, 8, 11, 15]
   RETURN, table[index]
END

FUNCTION Add_M_Up, val_1, val_2
   retValue = Add_M_Up_Look_M_Up(val_1) + Add_M_Up_Look_M_Up(val_2)
   RETURN, retValue
END

Writing your programs like this will solve all your file naming problems. (Well, at least to within single precision accuracy.)

[Return to IDL Programming Tips]