6352 Rate this article:
No rating

Simplifying Code Libraries and Object Access By Developing Static Methods

Benjamin Foreback

Another new feature in IDL 8.3 is the ability to create static methods on classes. A static method is a method, either a procedure method or function method, which can be called from outside the class without needing an instance of the class. They can be called using the "dot" syntax, and, from the outside, they work just like regular IDL routines or functions. There are a number of potential uses for static methods. This article will discuss grouping library routines and will also discuss easy access to singleton object operations. To define a method as static, add 'static' to the method's COMPILE_OPT statement.

Static methods can make code libraries much easier to develop and manage by allowing routines to be grouped into categories. IDL has already made some of its built-in class methods static, such as Clipboard.

Prior to IDL 8.3, every user-written helper routine either needed to be in its own file or else the full file in which it is located needed to be compiled before it could be used. Here is an example of a pre-IDL8.3 file that contains multiple helper routines:

PRO helper1
  
  PRINT, 'Helper 1 was called.'
  
END

PRO helper2

  PRINT, 'Helper 2 was called.'

END

PRO helper_routines

; This is a placeholder routine.

END

In order to call either helper1 or helper2, the caller must first call RESOLVE_ROUTINE, 'helper_routines'; otherwise an error would occur. By grouping these routines into static methods, however, IDL will automatically compile the methods when needed, provided that the file is in IDL's path, and the user does not need to manually resolve them. Here is an example of grouping the helpers into a class:

PRO helper_class::helper1
  COMPILE_OPT static

  PRINT, 'Helper 1 was called'

END

PRO helper_class::helper2
  COMPILE_OPT static

  PRINT, 'Helper 2 was called'

END

PRO helper_class__define

  !null = {helper_class, $
    INHERITS IDL_Object}

END

For purposes of grouping routines, there will never be a need to create an instance of the class. Therefore, this class does not need an Init method; only the class definition is needed.

To call one of these routines, use the following syntax:

helper_class.helper1

and IDL will compile and run the routine. Not only does grouping these helper routines offer convenience of a common category name, it also helps prevent namespace conflicts. For example, you could create a second helper class, such as 'helper_class2' that also has a method called 'helper1', and there would not be a conflict between the two methods because they are part of different classes.

 

A second practical use for static methods is to provide easy access to singleton classes. In this example, there is a class called 'IDLDataPoint', and only one of these classes is ever going to be instanciated throughout the application. This class is stored in an application-wide common block, and its properties and methods need to be used in many parts of application.

Prior to IDL 8.3, any routine that needed to access this class must retrieve it out of the common block. However, in IDL 8.3, the object's methods can be made static (this includes GetProperty and SetProperty), allowing them to be called without having a direct reference to the object, and the only place where the work of retrieving the reference can be done within the method. The main trick to doing this is to call OBJ_VALID on self and then call the method recursively. Here is an example of the IDLDataPoint class:

FUNCTION IDLDataPoint::Init
  
  self.name = 'IDL Data Point'
  self.value = 5L

  RETURN, 1

END

PRO IDLDataPoint::GetProperty, NAME=name, VALUE=value
  COMPILE_OPT static

  IF ~OBJ_VALID(self) THEN BEGIN
    COMMON IDLDataPoint_Common, dataPointObj
    dataPointObj.GetProperty, NAME=name, VALUE=value
    RETURN
  ENDIF
  
  IF ARG_PRESENT(name) THEN BEGIN
    name = self.name
  ENDIF
  
  IF ARG_PRESENT(value) THEN BEGIN
    value = self.value
  ENDIF

END

PRO IDLDataPoint::SetProperty, NAME=name, VALUE=value
  COMPILE_OPT static

  IF ~OBJ_VALID(self) THEN BEGIN
    COMMON IDLDataPoint_Common, dataPointObj
    dataPointObj.SetProperty, NAME=name, VALUE=value
    RETURN
  ENDIF
  
  IF N_ELEMENTS(name) GT 0 THEN BEGIN
    self.name = name
  ENDIF
  
  IF N_ELEMENTS(value) GT 0 THEN BEGIN
    self.value = value
  ENDIF
  
END

FUNCTION IDLDataPoint::MultiplyValue, multiplier
  COMPILE_OPT static
  
  IF ~OBJ_VALID(self) THEN BEGIN
    COMMON IDLDataPoint_Common, dataPointObj
    RETURN, dataPointObj.MultiplyValue(multiplier)
  ENDIF
  
  RETURN, multiplier * self.value
  
END

PRO IDLDataPoint__Define

  !null = {IDLDataPoint, $
    inherits IDL_Object, $
    name:'', $
    value:0L}
    
END


Create the class and store it in the common block with this routine:

PRO create_datapoint_class

  COMMON IDLDataPoint_Common, dataPointObj
  
  dataPointObj = OBJ_NEW('IDLDataPoint')

END

Now, without ever needing to get the IDLDataPoint class’s instance, you can do everything with this object that you could if you had an instance. Here is some code that shows property access and using a method:

PRINT, IDLDataPoint.NAME

IDL prints:

IDL Data Point

PRINT, IDLDataPoint.VALUE

IDL prints:

5

IDLDataPoint.VALUE=6

result = IDLdataPoint.MultiplyValue(4)

PRINT, result

IDL prints:

24

Thank you for reading. I hope this information is helpful.

Please login or register to post comments.