Category "Objects"

The recent article about how to investigate object code got me thinking about the various methods I use to find out about an object/class.

The code in the article, for the example of an object of class IDLgrColorBar, prints:

IDL> ab_obj_info, 'idlgrcolorbar'
Superclass: IDLGRMODEL

as well as some HTML information listing the methods of the objects.

One of the most useful techniques for me is one of my library routines to find the class hierarchy of an object:

IDL> mg_class_hierarchy, idlgrcolorbar()

This gives the same top-level information with a bit more detail (IDLgrContainer inherits from both IDL_Container and IDLitComponent), but does not provide any listing of the methods. If you know the name of the method, you can use another of my library routines to find out about it’s arguments:

IDL> man, 'idlgrcolorbar::computedimensions'
Filename: /Applications/exelis/idl85/lib/
result = idlgrcolorbar::computedimensions(self, osrcdest, PATH=path)

So I added a METHODS keyword to print out the methods of each class:

IDL> mg_class_hierarchy, 'idlgrcolorbar', /methods
    result = idlgrcolorbar::computedimensions()
    result = idlgrcolorbar::init()
      result = idlgrmodel::getctm()
      result = idlgrmodel::getxyzrange()
      result = idlgrmodel::init()

IDLdoc produces these docs, which list the methods of IDLgrColorBar and the hierarchy of superclasses along with a lot of other information including comments that might be in the code headers, but not the methods inherited from those superclasses.

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.

Continue reading “IDL 8.5: function pointers.”

The biggest change introduced by IDL 8.4 is the treatment of all variables as objects. Every variable now has attributes that you would normally get returned from the SIZE function: length, ndim, dim, tname, typecode, and typename. For example:

IDL> a = bindgen(2, 3)
IDL> print, a.length
IDL> print, a.ndim
IDL> print, a.dim
           2           3
IDL> print, a.tname

There are also static methods available for all variables:

IDL> n = 50
IDL> print, n->toString()

Strings, numbers, integers, and pointers have their own set of special methods appropriate for their respective types. For example integers have some handle base conversion methods:

IDL> print, n->toHex()
IDL> print, n->toBinary()

Strings have some methods that are not available through other IDL library routines, including the very useful replace method:

IDL> s = 'ITT VIS'
IDL> print, s.replace('ITT', 'Exelis')
Exelis VIS

Ronn Kling’s Object Oriented Programming with IDL is an excellent introduction to object-oriented programming with IDL. The beginning chapters introduce object-oriented concepts like encapsulation, inheritance, and polymorphism along with IDL’s basic syntax for creating classes. This should be straight-forward for anyone comfortable with writing normal routines in IDL.

Later chapters cover more sophisticated topics like features added in IDL 8.0 like object overloading, garbage collection, and the new syntax for calling methods and instantiating an object. There is also a chapter and appendix dedicated to showing tricks for getting around the lack of object-oriented features in IDL.

Overall, this is a great way to break the ice into object-oriented programming if you have been reluctant. Kling not only gives the basic syntax for IDL, but gives a nice introduction to object-oriented programming itself, as well as a discussion of situations when it can be most useful.

Operator overloading is the feature in IDL 8.0 that I have been testing the most; I am already using it in a couple of my projects. The behavior of objects when used in expressions containing nearly any of IDL’s operators can be defined through special methods of the object.

Continue reading “IDL 8.0: Operator overloading.”

ITT VIS is doing an object-oriented programming in IDL webinar on October 21.

It is frequently useful for applications to store information between runs. In general, if it is important enough to ask the user, it is important enough to remember. IDL provides a handy routine APP_USER_DIR to get a directory to store this type of information, but you are on your own reading and writing these preferences (unfortunately, PREF_SET and PREF_GET don’t allow application defined or user-defined preferences). MG_Prefs (code, docs) handles the dirty work for you by creating and restoring a SAV file for each of your preferences. This is a bit heavy-handed, but it means you store nearly anything as a preference value.

The class is intended to be simple to use. To store a preference do

prefs = obj_new('mg_prefs', author='mgalloy', application='myapp')
prefs->set, 'last_edited', 'myfile.txt'

Then in a later IDL session this preference can be retrieved with

prefs = obj_new('mg_prefs', author='mgalloy', application='myapp')
lastEdited = prefs->get('last_edited')

The template class is the basis for all the output in IDLdoc. In the process of releasing IDLdoc 3.0, some additions were necessary to facilitate outputting more complex hierarchical data.

Previously, the template process method took a structure argument and substituted variables in the template by the corresponding field name in the structure. The new version uses objects (but still allows structures). Any object with a getVariable method that follows the following signature:

function classname::getVariable, name, found=found

can be passed to the MGffTemplate::process method. When a name is encountered in the template, the template object calls getVariable with the variable name. This is much more flexible because variable requests can be handled in many ways: inherited from a parent class, delegated to another object, retrieved from a member variable, or retrieved in some other way (array, hash table, etc). Also, output can added to an object hierarchy by just adding a method instead of creating special structures.

The files needed to use the template are the MGffTemplate class (docs) and the MGffTokenizer class (docs).

See these previous posts about the template class.

True random numbers cannot be generated by a computer, but there are devices that can be connected to a computer that will generate true random numbers. Since not everyone has one of these devices, there are services that make these random numbers available through the internet.

Try for random integers, sequences, and strings derived from atmostpheric noise. I have a simple class that uses the new IDLnetURL to access the website. It can be used like:

IDL> rnd = obj_new('MGrndRandom')   
IDL> result = rnd->getIntegers(5, min=0, max=99, error=error)
IDL> help, error
ERROR           LONG      =            0
IDL> help, result
RESULT          LONG      = Array[5]
IDL> print, result
          63          63          88          62          53

The class is available in my library (source, docs).

Continue reading “True random number generators.”

I added methods to MGTestCase which are called before (setup) and after (tearDown) each test. Uses of these methods would be to create (and destroy) some common data for each of the tests in the MGTestCase, to time each test, or to do any task that must be done on a test-by-test basis as opposed to before and after all the tests in a MGTestCase (init and cleanup do that).

See “Unit testing framework” for an overview of the unit test framework.

Here’s an archive of all files needed and the docs for all the source code.

older posts »