Using Caché Objects
Object-Specific ObjectScript Features
[Back] [Next]
   
Server:docs2
Instance:LATEST
User:UnknownUser
 
-
Search:    

Caché ObjectScript includes features specific to working with classes and objects. These are:

When viewing this book online, use the preface of this book to quickly find related topics.
Relative Dot Syntax (..)
The relative dot syntax (..) provides a mechanism for referencing a method or property in the current context. The context for an instance method or a property is the current instance; the context for a class method is the class in which the method is implemented. You cannot use relative dot syntax in a class method to reference properties or instance methods, because these require the instance context.
For example, suppose there is a Bricks property of type %Integer:
Property Bricks As %Integer;
A CountBricks() method can then refer to Bricks with relative dot syntax:
Method CountBricks()
{
    Write "There are ",..Bricks," bricks.",!
}
Similarly, a WallCheck() method can refer to CountBricks() and Bricks:
Method WallCheck()
{
    Do ..CountBricks()
    If ..Bricks < 100 {
        Write "Your wall will be small."
    }
}
##Class Syntax
The ##class syntax allows you to:
Note:
##class is not case-sensitive.
Invoking a Class Method
To invoke a class method, the syntax is either of the following:
>Do ##class(Package.Class).Method(Args)
>Set localname = ##class(Package.Class).Method(Args)
It is also valid to use ##class as part of an expression, as in
 Write ##class(Class).Method(args)*2
without setting a variable equal to the return value.
A frequent use of this syntax is in the creation of new instances:
>Set LocalInstance = ##class(Package.Class).%New()
Casting a Method
To cast a method of one class as a method of another class, the syntax is either of the following:
>Do ##class(Package.Class1)Class2Instance.Method(Args)
>Set localname = ##class(Package.Class1)Class2Instance.Method(Args)
You can cast both class methods and instance methods.
For example, suppose that two classes, MyClass.Up and MyClass.Down, both have Go() methods. For MyClass.Up, this method is as follows
Method Go()
{
    Write "Go up.",!
}
For MyClass.Down, the Go() method is as follows:
Method Go()
{
    Write "Go down.",!
}
You can then create an instance of MyClass.Up and use it to invoke the MyClass.Down.Go method:
>Set LocalInstance = ##class(MyClass.Up).%New()
 
>Do ##class(MyClass.Down)LocalInstance.Go()
Go down.
It is also valid to use ##class as part of an expression, as in
 Write ##class(Class).Method(args)*2
without setting a variable equal to the return value.
A more generic way to refer to other methods are the $METHOD and $CLASSMETHOD functions, which are for instance and class methods, respectively; these are described in the Dynamically Accessing Objects section, later in this chapter. These provide a mechanism for referring to packages, classes, and methods programmatically.
Accessing a Class Parameter
To access a class parameter, you can use the following expression:
##class(Package.Class).#PARMNAME
Where Package.Class is the name of the class and PARMNAME is the name of the parameter. For example:
 w ##class(%XML.Adaptor).#XMLIGNOREINVALIDTAG
 
You can also use the $PARAMETER functions, which is described in the Dynamically Accessing Objects section, later in this chapter.
$this Syntax
The $this variable provides a handle to the OREF of the current instance, such as for passing it to another class or for another class to refer to the properties or methods of the current instance. When an instance refers to its own properties or methods, relative dot syntax is faster and thus is preferred.
Note:
$this is not case-sensitive; hence, $this, $This, $THIS, or any other variant all have the same value.
For example, suppose there is an application with an Accounting.Order class and an Accounting.Utils class. The Accounting.Order.CalcTax() method calls the Accounting.Utils.GetTaxRate() and Accounting.Utils.GetTaxableSubtotal() methods, passing the city and state values of the current instance to the GetTaxRate() method and passing the list of items ordered and relevant tax-related information to GetTaxableSubtotal(). CalcTax() then uses the values returned to calculate the sales tax for the order. Hence, its code is something like:
Method CalcTax() As %Numeric
{
    Set TaxRate = ##class(Accounting.Utils).GetTaxRate($this)
    Write "The tax rate for ",..City,", ",..State," is ",TaxRate*100,"%",!
    Set TaxableSubtotal = ##class(Accounting.Utils).GetTaxableSubTotal($this)
    Write "The taxable subtotal for this order is $",TaxableSubtotal,!
    Set Tax = TaxableSubtotal * TaxRate
    Write "The tax for this order is $",Tax,!
}
The first line of the method uses the ##Class syntax (described above) to invoke the other method of the class; it passes the current object to that method using the $this syntax. The second line of the method uses relative dot syntax to get the values of the City and State properties. The action on the third line is similar to that on the first line.
In the Accounting.Utils class, the GetTaxRate() method can then use the handle to the passed-in instance to get handles to various properties — for both getting and setting their values:
ClassMethod GetTaxRate(OrderBeingProcessed As Accounting.Order) As %Numeric
{
    Set LocalCity = OrderBeingProcessed.City
    Set LocalState = OrderBeingProcessed.State
    // code to determine tax rate based on location and set
    // the value of OrderBeingProcessed.TaxRate accordingly
    Quit OrderBeingProcessed.TaxRate
}
The GetTaxableSubtotal() method also uses the handle to the instance to look at its properties and set the value of its TaxableSubtotal property.
Hence, the output at the Caché terminal from invoking the CalcTax() method for MyOrder instance of the Accounting.Order class would be something like:
>Do MyOrder.CalcTax()
The tax rate for Cambridge, MA is 5%
The taxable subtotal for this order is $79.82
The tax for this order is $3.99
##super Syntax
Suppose that a subclass method overrides a superclass method. From within the subclass method, you can use the ##super() syntax to invoke the overridden superclass method.
Note:
##super is not case-sensitive. Also note that, unlike other features in this chapter, ##super() is available within Basic methods as well as within ObjectScript methods.
For example, suppose that the class MyClass.Down extends MyClass.Up and overrides the Simple class method. If the code for MyClass.Up.Simple() is:
ClassMethod Simple()
{
    Write "Superclass.",!
}
and the code for MyClass.Down.Simple() is:
ClassMethod Simple()
{
    Write "Subclass.",!
    Do ##super()
}
then the output for subclass method, MyClass.Down.Simple(), is:
>Do ##Class(MyClass.Down).Simple()
Subclass.
Superclass.
>
A more generic way to refer to other methods are the $METHOD and $CLASSMETHOD functions, which are for instance and class methods, respectively; these are described in the Dynamically Accessing Objects section, later in this chapter. These provide a mechanism for referring to packages, classes, and methods programmatically.
Calls That ##super Affects
##super only affects the current method call. If that method makes any other calls, those calls are relative to the current object or class, not the superclass. For example, suppose that MyClass.Up has MyName() and CallMyName() methods:
Class MyClass.Up Extends %Persistent
{

ClassMethod CallMyName()
{
    Do ..MyName()
}

ClassMethod MyName()
{
    Write "Called from MyClass.Up",!
}

}
and that MyClass.Down overrides those methods as follows:
Class MyClass.Down Extends MyClass.Up
{

ClassMethod CallMyName()
{
    Do ##super()
}

ClassMethod MyName()
{
    Write "Called from MyClass.Down",!
}

}
then invoking the CallMyName() methods have the following results:
USER>d ##class(MyClass.Up).CallMyName()
Called from MyClass.Up
 
USER>d ##class(MyClass.Down).CallMyName()
Called from MyClass.Down
MyClass.Down.CallMyName() has different output from MyClass.Up.CallMyName() because its CallMyName() method includes ##super and so calls the MyClass.Up.CallMyName() method, which then calls the uncast MyClass.Down.MyName() method.
##super and Method Arguments
##super also works with methods that accept arguments. If the subclass method does not specify a default value for an argument, make sure that the method passes the argument by reference to the superclass.
For example, suppose the code for the method in the superclass (MyClass.Up.SelfAdd()) is:
ClassMethod SelfAdd(Arg As %Integer)
{
    Write Arg,!
    Write Arg + Arg
}
then its output is:
>Do ##Class(MyClass.Up).SelfAdd(2)
2
4
>
The method in the subclass (MyClass.Down.SelfAdd()) uses ##super and passes the argument by reference:
ClassMethod SelfAdd(Arg1 As %Integer)
{
    Do ##super(.Arg1)
    Write !
    Write Arg1 + Arg1 + Arg1
}
then its output is:
>Do ##Class(MyClass.Down).SelfAdd(2)
2
4
6
>
In MyClass.Down.SelfAdd(), notice the period before the argument name. If we omitted this and we invoked the method without providing an argument, we would receive an <UNDEFINED> error.
Dynamically Accessing Objects
Caché supplies several functions that support generalized processing of objects. They do this by allowing a reference to a class and one of its methods or properties to be computed at runtime. (This is known as reflection in Java.) These functions are:
The function names are shown here in all uppercase letters, but they are, in fact, not case-sensitive.
$CLASSNAME
This function returns the name of a class. The signature is:
$CLASSNAME(Instance)
where Instance is an OREF.
For more information, see the $CLASSNAME page in the Caché ObjectScript Reference.
$CLASSMETHOD
This function executes a named class method in the designated class. The signature is:
$CLASSMETHOD (Classname, Methodname, Arg1, Arg2, Arg3, ... )
where
Classname An existing class.
Methodname A method of the class specified by the first argument.
Arg1, Arg2, Arg3, ... A series of expressions to be substituted for the arguments to the designated method.
For more information, see the $CLASSMETHOD page in the Caché ObjectScript Reference.
$METHOD
This function executes a named instance method for a specified instance of a designated class. The signature is:
$METHOD (Instance, Methodname, Arg1, Arg2, Arg3, ... )
where
Instance An OREF of instance of a class.
Methodname A method of the class specified by the instance in the first argument.
Arg1, Arg2, Arg3, ... A series of expressions to be substituted for the arguments to the designated method.
For more information, see the $METHOD page in the Caché ObjectScript Reference.
$PARAMETER
This function returns the value of a class parameter of the designated class. The signature is:
$PARAMETER(Instance,Parameter)
where:
Instance Either the fully qualified name of a class or an OREF of an instance of the class.
Parameter A parameter of the given class.
For more information, see the $PARAMETER page in the Caché ObjectScript Reference.
$PROPERTY
This function gets or sets the value of a property in an instance of the designated class. If the property is multidimensional, the following arguments after the property name are used as indices in accessing the value of the property. The signature is:
$PROPERTY (Instance, PropertyName, Index1, Index2, Index3... )
where:
Instance An OREF of instance of a class.
PropertyName A property of the class specified by the instance in the first argument.
Index1, Index2, Index3, ... For multidimensional properties, indices into the array represented by the property.
For more information, see the $PROPERTY page in the Caché ObjectScript Reference.
i%<PropertyName> Syntax
This section provides some additional information on instance variables. You do not need to refer to these variables unless you override an accessor method for a property; see the chapter Using and Overriding Property Methods.”
When you create an instance of any class, Caché creates an instance variable for each non-calculated property of that class. The instance variable holds the value of the property. For the property PropName, the instance variable is named i%PropName, and this variable name is case-sensitive. These variables are available within any instance method of the class.
For example, if a class has the properties Name and DOB, then the instance variables i%Name and i%DOB are available within any instance method of the class.
Internally, Caché also uses additional instance variables with names such as r%PropName and m%PropName, but these are not supported for direct use.
Instance variables have process-private, in-memory storage allocated for them. Note that these variables are not held in the local variable symbol table and are not affected by the Kill command.
..#<Parameter> Syntax
The ..#<Parameter> syntax allows for references to class parameters from within methods of the same class.
For example, if a class definition include the following parameter and method:
Parameter MyParam = 22;
and the following method:
ClassMethod WriteMyParam()
{
    Write ..#MyParam
}
Then the WriteMyParam() method invokes the Write command with the value of the MyParam parameter as its argument.