This chapter describes the rules and options for creating methods in InterSystems IRIS® classes and for calling those methods. Show
For information on calling instance methods, see the next chapter; such methods apply only to object classes. Introduction to MethodsA method is an executable element defined by a class. InterSystems IRIS supports two types of methods: instance methods and class methods. An instance method is invoked from a specific instance of a class and typically performs some action related to that instance. A class method is a method that can be invoked without reference to any object instance; these are called static methods in other languages. The term method usually refers to an instance method. The more specific phrase class method is used to refer to class methods. Because you cannot execute an instance method without an instance of an object, instance methods are useful only when defined in object classes. In contrast, you can define class methods in any kind of class. Defining MethodsTo add a class method to a class, add an element like the following to the class definition: ClassMethod MethodName(Arguments) as Classname [ Keywords] { //method implementation } Where:
To add an instance method to a class, use the same syntax with Method instead of ClassMethod: Method MethodName(arguments) as Classname [ Keywords] { //method implementation } Instance methods are relevant only in object classes. Specifying Method Arguments: BasicsA method can take any number of arguments. The method definition must specify the arguments that it takes. It can also specify the type and default value for each argument. (In this context, type refers to any kind of class, not specifically data type classes.) Consider the following generic class method definition: ClassMethod MethodName(Arguments) as Classname [ Keywords] { //method implementation } Here Arguments has the following general form: argname1 as type1 = value1, argname2 as type2 = value2, argname3 as type3 = value3, [and so on] Where:
For instance, here is a Calculate() method with three arguments: ClassMethod Calculate(count As %Integer, name, state As %String = "CA") { // ... } where count and state are declared as %IntegerOpens in a new tab and %StringOpens in a new tab, respectively. By default, arguments are of the %StringOpens in a new tab data type, so that an argument of unspecified type is a %StringOpens in a new tab. This is the case for name in the above example. Indicating How Arguments Are to Be PassedThe method definition also indicates, to programmers who might use the method, how each argument is expected to be passed. Arguments can be passed by value (the default technique) or by reference. See “Passing Arguments to a Method” later in this chapter. It may or may not be sensible to pass a specific argument by reference. The details depend upon the method implementation. Consequently, when you define a method, you should use the method signature to indicate to other programmers how each argument is meant to be used. To indicate that an argument should be passed by reference, include the ByRef modifier in the method signature, before the name of the argument. The following shows an example that uses ByRef for both its arguments: /// Swap value of two integers Method Swap(ByRef x As %Integer, ByRef y As %Integer) { Set temp = x Set x = y Set y = temp } Similarly, to indicate that an argument should be passed by reference and is intended to have no incoming value, include the Output modifier in the method signature, before the name of the argument. For example: Method CreateObject(Output newobj As MyApp.MyClass) As %Status { Set newobj = ##class(MyApp.MyClass).%New() Quit $$$OK } Specifying a Variable Number of ArgumentsYou can define a method that accepts variable numbers of arguments. To do so, include ... after the name of the last argument, as in the following example. This example also shows how this feature can be used. ClassMethod MultiArg(Arg1... As %String) { Set args = $GET(Arg1, 0) Write "Invocation has ", args, " element", $SELECT((args=1):"", 1:"s"), ! For i = 1 : 1 : args { Write "Argument[", i , "]:", ?15, $GET(Arg1(i), "<NULL>"), ! } } The following Terminal session shows how this method behaves: MYNAMESPACE>do ##class(VarNumArg.Demo).MultiArg("scooby","shaggy","velma","daphne","fred") Invocation has 5 elements Argument[1]: scooby Argument[2]: shaggy Argument[3]: velma Argument[4]: daphne Argument[5]: fred For more details on this feature, see the “Variable Numbers of Arguments” section of the “User-defined Code” chapter of Using ObjectScript. Returning a ValueTo define a method so that it returns a value, use either of the following in the method (if you implement the method in ObjectScript): Or: Where returnvalue is a suitable value for the method to return. This should be consistent with the declared return type of the method. If the return type is a data type class, the method should return a literal value. If the return type is an object class, the method should return an instance of that class (specifically an OREF). For details, see the chapter “Working with Registered Objects.” For example: ClassMethod Square(input As %Numeric) As %Numeric { Set returnvalue = input * input Return returnvalue } For another example, this method returns an object instance: ClassMethod FindPerson(id As %String) As Person { Set person = ##class(Person).%OpenId(id) Return person } The syntax for returning a value is different depending on the implementation language of the method. Restricting Access by Using Privilege ChecksYou can restrict access to a method by using the Requires keyword. Only users or processes that have the specified privilege (or privileges) can call the method. Specify a privilege by naming a resource and the appropriate level of permission (Use, Read, or Write), separated with a colon. Use a comma-delimited list to specify more than one privilege. In the following example, the MyAction method requires the Use permission on the Service_FileSystem resource: ClassMethod MyAction() [ Requires = "Service_FileSystem: Use" ] { write "You have access to this method." } Calling the method without the required privilege results in a <PROTECT> error: <PROTECT> *Method MyAction' requires resource 'Service_FileSystem: Use' If a method inherits the Requires keyword from a superclass, you can add to the list of required privileges by setting a new value for the keyword. You cannot remove required privileges in this manner. For details, see Privileges and Permissions in the Authorization Guide and Requires in the Class Definition Reference. Specifying the Implementation LanguageYou have the choice of implementation language when creating a method. In fact, within a single class, it is possible to have multiple methods implemented in different languages. All methods interoperate regardless of implementation language. By default, a method uses the language specified by the Language keyword of the class to which it belongs. For this keyword, the default is objectscript (ObjectScript). The other option is tsql (TSQL). You can override this for a specific method by setting the Language keyword for that method: Class MyApp.Test { Method TestC() As %Integer [ Language = objectscript ] { // This is ObjectScript Write "This is a test" Quit 1 } } Types of Methods (CodeMode Options)InterSystems IRIS supports four types of methods, which the class compiler handles differently:
Code MethodsA code method is a method whose implementation is simply lines of code. This is the most typical type of method and is the default. The method implementation can contain any code that is valid for the implementation language. Note: InterSystems IRIS comes with a set of system-defined methods that perform simple, common tasks. If a user-defined method performs one of these tasks, then the compiler does not generate any executable code for it. Rather, it associates the user-defined method with the system-defined method, so that invoking the user-defined method results in a call to the system-defined method, with an associated performance benefit. Also, the debugger does not step through such a system-defined method. Expression MethodsAn expression method is a method that may be replaced by the class compiler, in certain circumstances, with a direct in-line substitution of a specified expression. Expression methods are typically used for simple methods (such as those found in data type classes) that need rapid execution speed. For example, it is possible to convert the Speak() method of the Dog class from the previous example into an expression method: Method Speak() As %String [CodeMode = expression] { "Woof, Woof" } Assuming dog refers to a Dog object, this method could be used as follows: Which could result in the following code being generated: It is a good idea to give default values to all formal variables of an expression method. This prevents potential inline substitution problems caused by missing actual variables at runtime. Note: InterSystems IRIS does not allow macros or call-by-reference arguments within expression methods. Call MethodsA call method is a special mechanism to create method wrappers around existing InterSystems IRIS routines. This is typically useful when migrating legacy code to object-based applications. Defining a method as a call method indicates that a specified routine is called whenever the method is invoked. The syntax for a call method is: Method Call() [ CodeMode = call ] { Tag^Routine } where “Tag^Routine” specifies a tag name within a routine. Method GeneratorsA method generator is actually a small program that is invoked by the class compiler during class compilation. Its output is the actual runtime implementation of the method. Method generators provide a means of inheriting methods that can produce high performance, specialized code that is customized to the needs of the inheriting class or property. Within the InterSystems IRIS library, method generators are used extensively by the data type and storage classes. For details, see “Defining Method and Trigger Generators.” Projecting a Method As an SQL Stored ProcedureYou can define a class method (but not an instance method) so that it is also available as an SQL stored procedure. To do so, include the SqlProc keyword in the method definition. The default name of the procedure is as CLASSNAME_METHODNAME To specify a different name, specify the SqlName keyword. For details, see “Defining Stored Procedures” in Using InterSystems SQL. Calling Class MethodsThis section discusses how to call class methods in ObjectScript. This section applies to all kinds of classes. Note that instance methods are discussed in the next chapter, because they apply only to object classes.
If the given method does not exist or if it is an instance method instead, the system generates the <METHOD DOES NOT EXIST> error. If the given method is private, the system generates the <PRIVATE METHOD> error. Passing Arguments to a MethodThe default way to pass arguments to methods is by value. In this technique, simply include the arguments as variables, literal values, or other expressions within the method call, as shown in the preceding examples. It is also possible to pass arguments by reference. This works follows: the system has a memory location that contains the value of each local variable. The name of the variable acts as the address to the memory location. When you pass a local variable to a method, you pass the variable by value . This means that the system makes a copy of the value, so that the original value is not affected. You can pass the memory address instead; this technique is known as calling by reference. It is also the only way to pass a multidimensional array as an argument. In ObjectScript, to pass an argument by reference, precede that argument with a period. For example: set MyArg(1)="value A" set MyArg(2)="value B" set status=##class(MyPackage.MyClass).MyMethod(.MyArg) In this example, we pass a value (a multidimensional array) by reference so that the method could receive the value. In other cases, it is useful to pass an argument by reference so that you can use its value after running the method. For example: set status=##class(MyPackage.MyClass).GetList(.list) //use the list variable in subsequent logic In other cases, you might specify a value for the variable, invoke a method that modifies it (and that returns it by reference), and then use the changed value. Casting a MethodTo cast a method of one class as a method of another class, the syntax is either of the following (in ObjectScript): 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 approach is to use the $METHOD and $CLASSMETHOD functions, which are for instance and class methods, respectively. These are described in earlier sections of this chapter. Overriding an Inherited MethodA class inherits methods (both class and instance methods) from its superclass or superclasses. Except for methods that are marked Final, you can override these definitions by providing a definition within this class. If you do so, note the following rules:
If your method implementation needs to call the method of the same name as defined in the superclass, you can use the syntax ##super(), which is discussed in the subsections. This discussion applies to code that is written in ObjectScript. ##super()Within a method, use the following expression to call the method of the same name as defined in the nearest superclass: You can use this expression with the DO command. If the method returns a value, you can use SET, or you can use it as part of another expression. The following shows some variations: do ##super() set returnvalue=##super()_"additional string" Note: ##super is not case-sensitive. This is useful if you define a method that should invoke the existing method of the superclass and then perform some additional steps such as modifying its returned value. ##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. 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. Number of ArgumentsIn some cases, you might find it necessary to add new arguments to a method in a superclass, thus resulting in more arguments than are defined in the method in a subclass. The subclasses will still compile, because (for convenience) the compiler appends the added arguments to the method in the subclass. In most cases, you should still examine all the subclasses that extend the method, and edit the signatures to account for the additional arguments, and decide whether you want to edit the code also. Even if you do not want to edit signatures or code, you still must consider two points:
When a method uses a class name as its return type?When a method uses a class name as its return type, the class of the type of the returned object must be either a subclass of, or the exact class of, the return type. Suppose that you have a class hierarchy in which ImaginaryNumber is a subclass of java. lang.
When a method's return type is specified as a class name what is actually returned to the calling program?When a method's return type is an object, what is actually returned to the calling program? only one copy of the field in memory. a case expression. Enumerated types have this method, which returns the position of an enum constant in the declaration list.
What is the return type of an method?Every method in Java is declared with a return type and it is mandatory for all java methods. A return type may be a primitive type like int, float, double, a reference type or void type(returns nothing). The type of data returned by a method must be compatible with the return type specified by the method.
What is the return type of the method in Java called?In Java, every method is declared with a return type such as int, float, double, string, etc. These return types required a return statement at the end of the method. A return keyword is used for returning the resulted value. The void return type doesn't require any return statement.
|