An important side effect of the IDL-Python bridge is to add some Python features to IDL in order to be able to effectively expose a Python API in IDL. One of these is the introduction of “function pointers”, a way of treating an object as a function. This is useful because objects have a lot of nice properties just from being a variable — they can be stored in a variable, passed to other functions, saved in a .sav file, etc. With the introduction of function pointers, functions have these same properties.

To define an object to be used as a function pointer, a class needs to inherit from IDL_Object and define an _overloadFunction method:

function my_class::_overloadFunction, arg1, arg2, arg3, ...

Then, an object instantiated from this class can be called like a function and this method will be called to produce the result:

IDL> compile_opt strictarr
IDL> obj = my_class()
IDL> print, obj(1, 2, 3)

The “strictarr” or “idl2” compile_opt is needed or IDL will use the _overloadBracketsLeftSide method.

For example, let’s define a simple class that represents the histogram equalization image processing operation in mg_hist_equal__define.pro:

;= operators

function mg_hist_equal::_overloadFunction, im
  compile_opt strictarr

  return, hist_equal(im, percent=self.percent, top=self.top)
end


;= property access

pro mg_hist_equal::setProperty, percent=percent, top=top
  compile_opt strictarr

  if (n_elements(percent) gt 0L) then self.percent = percent
  if (n_elements(top) gt 0L) then self.top = top
end


;= lifecycle methods

function mg_hist_equal::init, _extra=e
  compile_opt strictarr

  if (~self->IDL_Object::init()) then return, 0

  self->setProperty, _extra=e

  return, 1
end

pro mg_hist_equal__define
  compile_opt strictarr

  !null = { mg_hist_equal, inherits IDL_Object, $
            percent: 0.0, $
            top: 0 $
          }
end

The class defines a few properties that will be passed to the HIST_EQUAL function when called, but to be a function pointer, all that is needed is to inherit from IDL_Object and define the _overloadFunction method.

As an example of using this class, let’s read in an image:

IDL> dims = [248, 248]
IDL> file = filepath('convec.dat', subdir=['examples', 'data'])
IDL> mantle = read_binary(file, data_dims=dims)

Then define our function pointer:

IDL> he = mg_hist_equal(percent=10.0, top=255)

We could just call our function pointer like this:

IDL> equ_mantle = he(mantle)

But instead let’s define a function that applies any function pointer to a variable:

function mg_function_pointer_demo, im, op
  compile_opt strictarr

  return, op(im)
end

Then we can pass our function pointer to this function:

IDL> equ_mantle = mg_function_pointer_demo(mantle, he)
IDL> window, xsize=dims[0] * 2, ysize=dims[1]
IDL> tv, mantle, 0
IDL> tv, equ_mantle, 1

This code is in mg_function_pointer_demo.pro and can be called with:

IDL> .run mg_function_pointer_demo

Function pointers have many applications in such areas where an algorithm has a callback function such as fitting and optimization algorithms. The syntax of function pointers would be cleaner than passing function names as strings and also allows the various parameters of the function represented by the function pointer to be set before passing it.

See the IDL Data Point article for more information.