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 []:

;= operators

function mg_hist_equal::_overloadFunction, im
compile_opt strictarr

return, hist_equal(im, percent=self.percent,

;= 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 = top

;= 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

pro mg_hist_equal__define
compile_opt strictarr

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

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)

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 [] 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.

[IDL Data Point]: "New in IDL 8.5, Function Pointers and Dynamic Methods"

[]: ""
[]: ""