There are many other changes to the core IDL language besides operator overloading and lists/hashes, discussed here already. These changes make IDL’s syntax more convenient to use.

A new !null variable was introduced in IDL 8.0. There are several equivalent forms:

IDL> help, !null, [], {}
<Expression>    UNDEFINED = !NULL
<Expression>    UNDEFINED = !NULL
<Expression>    UNDEFINED = !NULL

!null is an undefined variable with a couple special properties:

  1. it can be assigned to a variable
  2. it can be used in array or structure concatenation

For example, a typical use would be:

IDL> a = []
IDL> a = [a, 1]

This eliminates the need for special cases in code to check for the case of adding the first element, though this use case is generally handled better by the new list objects.

IDL now allows the use of negative subscripts to specify indices relative to the end of an array, with -1 representing the last element:

IDL> a = findgen(10)
IDL> print, a[-1]
      9.00000
IDL> print, a[-2]
      8.00000

Negative indices can also be used in ranges:

IDL> print, a[-2:0:-1]
      8.00000      7.00000      6.00000      5.00000      4.00000
      3.00000      2.00000      1.00000      0.00000

But, negative subscripts are handled in the same manner as in older versions of IDL when placed in an array used to index another array:

IDL> print, a[[-1]]
      0.00000

This behavior can also still be controlled via compile_opt strictarrsubs.

Object-oriented programming has had several important updates. Most important of these features is automatic garbage collection. This will automatically free heap variables, both pointers and objects, which no longer have a reference to them. For example, in the following example, an object is created and then its reference is lost by reassignment to another value:

IDL> o = obj_new('IDL_Container')
IDL> help, /heap
Heap Variables:
    # Pointer: 0
    # Object : 1

<ObjHeapVar1>  refcount=1
                STRUCT    = -> IDL_CONTAINER Array[1]
IDL> o = 2
IDL> help, /heap
Heap Variables:
    # Pointer: 0
    # Object : 0

This situation would have resulted in leaked memory—the help, /heap command would have reported 1 object at the end, but it would not have been accessible through the o variable any longer. Now, memory that can no longer be accessed is automatically freed. This feature can be turned off globally or for a particular variable with the DISABLE keyword to the new HEAP_REFCOUNT function.

There are also two small syntax changes that make objects a bit more like other languages and a bit more convenient:

  1. method invocation can be done with the . operator, as well as the old -> operator
  2. a function of the same name as the class is automatically generated to create new objects of that class, so the OBJ_NEW function is not required to instantiate an object

These are both shown in the following:

IDL> c = IDL_Container()
IDL> c.add, IDLgrModel()
IDL> help, c.get(position=0)
<Expression>    OBJREF    = <ObjHeapVar5(IDLGRMODEL)>

Note that the . operator and the -> operator a slightly different precedence:

IDL> p = ptr_new(list())
IDL> *p->add, 1
IDL> *p.add, 1

*p.add, 1
         ^
% Syntax error.
IDL> (*p).add, 1

My understanding is that this is not intended and will be fixed in a release soon.