Scripted objects

Beanshell also provides scripted objects as a very convenient ability to program method closures, similar to JavaScript and other languages. Scripted objects function as lightweight objects, allowing a simple way to do object-oriented programming in a script. A scripted object is similar to a scripted method, the main differences being the conceptual design;

Let’s look at a simple scripted object:

Object strataValues(String leadSpecies, int siteClass, int martenStrata) {
    return this;
}    

This object is a simple data carrier for forest stratification values. The formal parameters to this method become local variables. We can tell that this is a scripted object because it returns the value 'this', which is a reference to 'this object'. The data type Object is the default for scripted objects, and it could have been omitted from the start of the method definition. As it stands this scripted object simply let's us store and retrieve local variable values by name.

sv = strataValues("DF", 1, 4);
print("Leading species code="+sv.leadSpecies+" site class="+sv.siteClass+
      " marten strata="+sv.martenStrata);

This scripted object is easier to use than an array because the data items are stored by name, and it allows mixtures of different data types within the same structure (in this case both String and int data types are being used). It is also simpler and requires fewer key strokes than using a HashMap as a dictionary.

Let's make a few enhancements to this object. First, we know that the site class value must be in the range of 1 to 8, and the marten strata code must be in the range of 1 to 4, and we can perform range checking to catch bad data inputs. Second, let's add a method that will return a combined strata label in a standard format. Finally, we will add a compareTo() method, from the Comparable interface, to provide a "natural ordering" for our objects. Having a compareTo() allows us to use sorting utilities to rearrange our list into what we consider to be it's natural order.

strataValues(String leadSpecies, int siteClass, int martenStrata) {  1
    if (siteClass < 1 || siteClass > 8)  2
        throw new IllegalArgumentException("Site class value out of range: " 3
                                           + siteClass);
    if (martenStrata < 1 || martenStrata > 4)
         throw new IllegalArgumentException("Marten strata value out of range:
        "+martenStrata);
       
    String getLabel() {  4
       return leadSpecies+"-"+siteClass+"-"+martenStrata;
    }

    public int compareTo(Object o) {  5
       result = leadSpecies.compareTo(o.leadSpecies);
       if (result == 0) { // if leadSpecies is equal then compare siteClass
           result = Integer.compare(siteClass, o.siteClass);
           if (result == 0) // if siteClass is equal then compare martenStrata
               result = Integer.compare(martenStrata, o.martenStrata);
       }
       return result;
    }
     
    return this;  6
} 

1

In this second example we have omitted the Object type declaration that was at the beginning of the method. Object is the default value and this keyword is not required.

2

A conditional test is performed on the input siteClass value.

3

If the siteClass value is found to be out of range an exception is thrown. The exception provides an informative message, and causes the object construction to be interrupted. The program execution is unwound to the closest enclosing catch block that has a signature to handle this exception. If no catch blocks are found then control returns to the location the initiated the command.

4

The getLabel() method is defined within the scripted object, and operated on the local variables.

5

The compareTo() function defined in this script fulfills the Comparable contract, and allows the objects to be used where comparable values are required. The script tests each component of the object in order, sorting first on leadSpecies, then (if required) on siteClass, and finally (if required) on martenStrata.

6

The last statement in the method returns the 'this' reference, which is the marker of a scripted object.

Here is a trivial example of how this object could be used:

list = new ArrayList();
list.add(strataValues("DF", 1, 4));
list.add(strataValues("CE", 2, 3));
Collections.sort(list);

System.out.println("Strata codes in sorted order:");
for (Object o : list)
    System.out.println(o.getLabel());

Of course a more sophisticated example would load do much more, such as loading the list from a text file or data table and setting up accounts or targets.

Although not apparent from these trivial examples, scripted object are a powerful and easy to use implementation of the object oriented paradigm, and can greatly simplify some programming tasks. For more information about scripted objects see the BeanShell documentation for scripted objects.