Show/Hide Toolbars



Declare a method name and an optional list of local variable names.


 [Attributes] [Modifiers] METHOD <idMethod>


 [([<idParam> [AS | REF|OUT|IN <idType>] [, ...])]

 [AS <idType>]


 [CLASS <idClass>]

 [=> <expression>]




AttributesAn optional list of one or more attributes that describe meta information for am entity, such as for example the [TestMethod] attribute on a method/function containing tests in a MsTest class library. Please note that Attributes must be on the same line or suffixed with a semi colon when they are written on the line above that keyword.


ModifiersAn optional list of modifiers that specify the visibility or scope of the entity, such as PUBLIC, PROTECTED, HIDDEN, INTERNAL, SEALED, ABSTRACT or STATIC.


<idMethod>A valid identifier name for the method.  Method names must be unique within a class, but can share the same name as other entities (including access and assign methods) in your application.


TypeParametersThis is supported for methods with generic type arguments. This something like <T> for a method with one type parameter named T. Usually one of the parameters in the parameter list is then also of type T.


<idParam>A  parameter variable.  A variable specified in this manner is automatically declared local.  These variables, also called formal parameters, are used to receive arguments that you pass when you call the entity.


AS | REF|OUT|IN <idType>Specifies the data type of the parameter variable (called strong typing).  AS indicates that the parameter must be passed by value, and REF indicates that it must be passed by reference with the @ operator. OUT is a special kind of REF parameter that does not have to be assigned before the call and must be assigned inside the body of the entity. IN parameters are passed as READONLY references.
The last parameter in the list can also be declared as PARAMS <idType>[] which will tell the compiler that the function/method may receive zero or more optional parameters.
Functions or Methods of the CLIPPER calling convention are compiled to a function with a single parameter that this declared as Args PARAMS USUAL[]


AS <idType>Specifies the data type.  If omitted, then depending on the compiler options the type will be either USUAL or determined by the compiler.


TypeParameterConstraintsHere you can specify constraints for the Type parameters, such as WHERE T IS SomeName or WHERE T IS New


<idConvention>Specifies the calling convention for this entity.  <idConvention> must be one of the following:

o        CLIPPER

o        STRICT

o        PASCAL

o        CALLBACK

o        THISCALL

Most calling conventions are for backward compatibility only.
There are 2 exceptions:
CLIPPER declares that a method has untyped parameters. This is usually only needed for methods without any declared parameters. Otherwise the compiler will assume CLIPPER calling convention when it detects untyped parameters.
Methods and Functions in external DLL may have STRICT, PASCAL, CALLBACK


CLASS <idClass>The class to which this method belongs. This clause is mandatory for entities declared outside of a CLASS .. END CLASS construct
=> <Expression>Single expression that replaces the multiline body for the entity. CANNOT be compiled with a body


<Body>Program statements that form the code of this entity.
The <Body> can contain one or more RETURN statements to return control to the calling routine and to serve as the function return value.  If no return statement is specified, control passes back to the calling routine when the function definition ends, and the function will return a default value depending on the return value data type specified (NIL if the return value is not strongly typed).
CANNOT be combined with an Expression Body


END METHODOptional end clause to indicate the end of the inline METHOD entity


A method is a subprogram comprised of a set of declarations and statements to be executed whenever you refer to the method using the message send operator, as in:








Classes, instance variables (see the CLASS statement in this guide), and methods are the basic object-oriented programming units.  You will use methods in your applications to organize computational blocks of code for a specific class of objects.


The Start() method: All applications must either have one function or procedure named Start().  
Start() serves as the startup routine when the application is executed.  Start() must be declared without parameters or with an string array parameter and must either have an Int return value or of type Void


VO Compatibility:


VO has 2 special method names for constructing and destructing class objects: Init() and Axit().
In X# These methods should be named CONSTRUCTOR and DESTRUCTOR.

If you compile with compiler option /vo1 then you can still use the 'old' names. The compiler will then automatically map the Init() method to constructor and the Axit() method to destructor. This is NOT recommended.


The Init() method: If you define a method named Init(), it is called automatically when you create an instance of the class to which the method belongs.  Arguments listed within the instantiation operators ({}) are passed as parameters to the Init() method.  Common uses for the Init() method are to initialize instance variables, allocate memory needed by the object, register the object, create subsidiary objects, and set up relationships between objects.


The Axit() method: You do not need to deallocate memory used by objects because the garbage collector takes care of this for you automatically.  However, in some cases an object can manage other resources that do need proper disposition.  For example, if an object opens a database only for its own use, it should close it when it is finished and make the work area available for other uses.


If you register an object with the RegisterAxit() function, for example in the Init() method, and provide a method named Axit(), this Axit() method will automatically be called by the garbage collector just before the object is destroyed.  Thus, in the Axit() method you can close databases, deallocate memory, or close communications links.


NoIVarGet()/NoIVarPut() methods: If you define methods named NoIVarGet() and NoIVarPut(), they will automatically be invoked if an instance variable that does not exist is referenced.  They are called with the instance variable name as a parameter, in the form of a symbol and, in the case of NoIVarPut(), with the assigned value.  This feature is useful in detecting and preventing a runtime error and for creating virtual variables dynamically at runtime.  For example, the DBServer class uses this technique to make the database fields appear to be exported instance variables of a database object:


METHOD NoIVarGet(symFieldName) CLASS DBServer
    RETURN FieldGetAlias(symAlias, symFieldName)
    // Pass it up if it was not a field name
METHOD NoIVarPut(symFieldName, uValue) ;
  CLASS DBServer
    RETURN FieldGetAlias(symAlias, ;
        symFieldName, uValue)
    // Pass it up if it was not a field name
    SUPER:NoIVarPut(symFieldName, uValue)
FUNCTION DatabaseTest()
  LOCAL oDBServer AS DBServer
  oDBServer := DBServer{"customer"}
  ? oDBCustomer:CustName
  oDBCustomer:ZipCode := "12345"


The NoMethod() method: If you define a method named NoMethod(), it will automatically be invoked if a method name that you invoke within the same class cannot be found.  The arguments passed will be the same as the original method.  This feature is useful in detecting and preventing a runtime error when a method cannot be found.  Use the NoMethod() function to find out the name of the method that could not be found.


Exporting locals through code blocks: When you create a code block, you can access local variables defined in the creating entity within the code block definition without having to pass them as parameters (i.e., local variables are visible to the code block).  Using this fact along with the fact that you can pass a code block as a parameter, you can export local variables.  For example:


 cbAdd := {|nValue| nValue + nVar}
 ? SELF:Two(cbAdd)                // Result:  210
METHOD Two(cbAddEmUp) CLASS MyClass
 RETURN EVAL(cbAddEmUp,200)

When the code block is evaluated in Two(), nVar, which is local to method One(), becomes visible even though it is not passed directly as a parameter.


Invoking methods: The syntax to invoke a method of an object is as follows:


where <uArgList> is an optional comma-separated list of arguments to pass to the named method.  <idObject> identifies the object to whom the method invocation is to be sent; to refer to the same object within a method you use SELF:  or SUPER:  (see note below) instead of <idObject>:.


You can invoke a method within an expression or as a program statement.  If called as a program statement, the return value is ignored.


You can also use a method invocation as an aliased expression by prefacing it with an alias and enclosing it in parentheses:




When you do this, the work area associated with <idAlias> is selected, the method is executed, and the original work area is reselected.  You can specify an aliased expression as a program statement, as you would any other expression.

A method can call itself recursively.  This means you can refer to a method in its own <MethodBody>.



The visibility of typed methods can also be influenced by using the HIDDEN and PROTECT modifiers as in their use with instance variables.  SUPER calls of HIDDEN methods in parent classes cannot be done by methods of the sub-classes.


Calling convention: Methods use the CLIPPER calling convention, unless they are strongly typed.  See the FUNCTION statement in this guide for more information.


SELF and SUPER: SELF is a special variable that contains a reference to the object that is the receiver of a message (a message is sent to an object each time you use the send operator to invoke a method or access an instance variable).  Whenever a message is sent to an object, a reference to the object is placed in SELF before the corresponding method is invoked.  Within methods of the class, you must use SELF with the message send operator (:) to send messages to the current object.  Using SELF:  to access instance variables is optional; see the ACCESS and ASSIGN entries in this guide for details on when it is required (it is always allowed).


SUPER is another special variable that contains a reference to the class that is the nearest ancestor of the method lookup.  It passes a message up the inheritance tree to the appropriate superclass and is meaningful only if the current object's class inherits from another class.  You can use SUPER with the message send operator (:) to refer directly to a method defined in a superclass.  If you redefine a method in a subclass (by creating a method with the same name as one in a superclass), SUPER is the only way you can override the redefined method with the superclass version.

SUPER:  is useful when defining a subclass which adds some unique behavior, but nonetheless inherits standard behavior from its superclass.  For example:


CLASS Person
METHOD Init(cFirstName, cLastName) CLASS Person
 cName := cFirstName + " " + cLastName
 symName := String2Symbol(cName)
CLASS Customer INHERIT Person
METHOD Init(cFirstName, cLastName, nCustNo) ;
         CLASS Customer
 SUPER:Init(cFirstName, cLastName)
 wCustNo := nCustNo


The SELF and SUPER variables are allowed only in method definitions.  SELF is the default return value for all methods.


Parameters: As an alternative to specifying method parameters in the METHOD declaration statement, you can use a PARAMETERS statement to specify them.  This practice, however, is not recommended because it is less efficient and provides no compile-time integrity validation.  See the PARAMETERS statement in this guide for more information.

Strongly  typed Methods


In addition to XSharp untyped method implementation, strong typing of method parameters and return values is now supported, providing you with a mechanism through which highly stable code can be obtained.  The type information supplied enables the compiler to perform the necessary type checking and, thus, guarantee a much higher stable code quality.


A further benefit obtained by utilizing strongly typed methods is that of performance.  The implementation of typed methods presumes that when the programmer employs strongly typed messages, the compiler can effectively perform an early binding for the respective methods invocation.  As a result of this implementation, typed methods invocations are somewhat faster than the respective untyped counterparts.  These advantages are, however, attained at the price of losing the flexibility which untyped methods offer.


It is, therefore, important to remember that interchangeably using both the typed and the untyped versions of a particular methods in an inheritance chain is neither permissible nor possible.


XSharp allows strong typing of METHODs, ACCESSes and ASSIGNs.  The programmer accomplishes the specification of the strongly typed methods with XSharp in two steps:


1.A mandatory declaration of the typed method is given in its respective class.
This declaration is reponsible for declaring the order of the methods in the so-called virtual table which XSharp employs for the invocation of typed methods.  A re-declaration of a method in a subclass is NOT permissible, since it would cause abiguity for the compiler.
2.Define the strongly typed method.  
Unlike strongly typed functions, method typing requires strongly typing of the method arguments, the method return value AND speficying a valid calling convention.  
The following calling conventions are valid for typed methods: STRICT, PASCAL or CALLBACK.


This example creates a class of two-dimensional coordinates with methods to initialize the coordinates, draw a grid, and plot the point:


 LOCAL oPointSet AS Point2D
 oPointSet := Point2D{2, 3}
CLASS Point2D                        // Define Point2D class
METHOD Init(iRow, iCol) CLASS Point2D
 x := iRow
 y := iCol
 @ x + 11, y + 36 SAY CHR(249)
METHOD ShowGrid() CLASS Point2D
 LOCAL iCounter AS INT
 FOR iCounter := 1 TO 21
         IF iCounter = 11
                 @ iCounter, 1 SAY REPLICATE(CHR(196), 71)
                 @ iCounter, 36 SAY CHR(197)
                 @ iCounter, 36 SAY CHR(179)

See Also