Getting Started Documentation Glish Learn More Programming Contact Us
Version 1.9 Build 1556
News FAQ
Search Home


next up previous contents home.gif
Next: Writing a GUI for Your Application Up: How to Write an AIPS++ Application Previous: General Interface Considerations


Writing an Application Solely in Glish

Applications in glish are conveniently written in the glish closure object idiom. In this idiom, the object contains both publically and privately visible functions and data. A full blown example is the imager module in the synthesis package. A simpler example is to be seen in the example of a tableplotter tool (this does not actually exist in the package):

pragma include once  
include "table.g";
include "plotter.g";
  
# Constructor for a table plotter object
const tableplotter:=function(tableplotterlogger=defaultlogger,         #1
	        	     tableplotterplotter=defaultplotter) {
    
# Private functions and data
#------------------------------------------------------------------------
  private:=[=];                                                           #2

# Convenience function: is this vector one-dimensional?                #3
  const private.is_1d:=function(vec) { ... };

# Public functions
#------------------------------------------------------------------------

  public:=[=];

# Is this object valid?                                                #4
  const public.ok:=function() {
    if(is_boolean(private.table)) fail "need to settable";                #5
    if(!private.is_1d(private.x.data)) fail "x is not a 1d vector";
    if(!private.is_1d(private.y.data)) fail "y is not a 1d vector";
    return T;
  }

# Delete this object: no-op for this implementation                    #6
  const public.delete:=function() {return T;}

# set and verify x
  const public.setx:=function(x, fn=F) {
    wider private;
    private.x.col:=x;
    private.x.data:=private.table.getcol(x);
    if(is_function(fn)) private.x.data:=fn(private.x.data);
    if(!private.is_1d(private.x.data)) fail paste("not a 1-d vector:",
      private.x.data::shape);
    return T;
  }

# set and verify y
  const public.sety:=function(y, fn=F) { ... }

# return a record containing the actual x and y to be plotted
  const public.getxy:=function() { ... }

# set and verify the table
  const public.settable:=function(tablename) { ... }

# autoscale
  const public.auto:=function() { ... }

# plot x vs y
  const public.plot:=function() { ... }
  
# return a reference to the public functions and data
  return ref public;
  
# end of the definition of tableplotter
  }

# Global Demonstration function
  const tableplotterdemo:=function() { ... }

# Global Test
  const tableplottertest:=function() { ... }

# Make standardly named tableplotter                                  #7
const defaulttableplotter:=tableplotter();

# Make standard abbreviation
const tp:=ref defaulttableplotter;

# log to the standard logger                                          #8
defaultlogger.log('', 'NORMAL', "defaulttableplotter ready for use", 'tableplotter');
defaultlogger.log('', 'NORMAL', "tp is short for defaulttableplotter", 'tableplotter');
  
} # include guard

An example of the use of this object is given below in section 6. Some comments on this code:

1.
Pass in resources that the user might wish to change.
2.
The basic trick of a closure object is that the public data and functions are attached to a record that is the returned value of the defining function (or constructor). The private functions are declared as part of a record (private) that is not visible externally.
3.
Define convenient but private functions as belonging to private.
4.
Provide a public method ok() that checks the status of the object. This returns either T if ok, or a fail if not ok. You should check the returned value of any method that you use.
5.
For error checking and notification, use the fail mechanism. Be sure to check the returned values from other glish functions to determine if a fail has occurred. If so, propagate it upwards by returning it. Careful and disciplined use of fails is essential to writing robust glish code.

Here is a simple example: the first function uses fail as an alternate return if the table does not exist. The second function therefore has to check for fail type and relay it. Of course, if the return is relayed directly then there is no need for any such checking. Similarly, fail as an input to another function guarantees a fail return some forms of checking can be omitted.

tablefromname:=function(tablename)
  {
    if(!tableexist(tablename)) fail "table does not exist";
    return tableopen(tablename);
  }

vs:=function(vsname)
  {
    public:=[=];
    result:=tablefromname(vs);
    if(is_fail(result)) return result;
    public.table:=result;
    return ref table;
  }

6.
All important attributes of real classes can be simulated using the closure object idiom except for destructors. This means that you have to provide and document a method (conventionally called done) that deactivates the object (e.g. deletes any open objects). This has to be used before the object is destroyed by Glish by, for example, going out of scope. Please provide this even if it does nothing for your implementation. If the implementation changes it may be needed in the future. As a corollary, be careful to use the delete method of any object, e.g. table, that you use.
7.
Since only one of these objects is probably present at any one time, we call it a tableplotter. The standard name for the default such object is thus defaulttableplotter. Since this is rather long-winded, we provide a standard abbrievation tp.
8.
If you are creating something, tell the user.


next up previous contents home.gif
Next: Writing a GUI for Your Application Up: How to Write an AIPS++ Application Previous: General Interface Considerations   Contents
Please send questions or comments about AIPS++ to aips2-request@nrao.edu.
Copyright © 1995-2000 Associated Universities Inc., Washington, D.C.

Return to AIPS++ Home Page
2006-10-15