Show/Hide Toolbars

XSharp

Purpose

Declare a method to access a non-exported or virtual instance variable.

Syntax

 [Attributes]  [Modifiers] ACCESS <idName>

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

 [AS <idType>] [<idConvention>]

 [CLASS <idClass>]

 [=> <expression>]

 CRLF

 [<Body>]

 [END ACCESS]

Arguments

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.

 

<idName>A valid identifier name for the instance variable whose access method you are defining.  Like other methods, access methods are entities; however, the system uses a unique naming scheme for them to prevent collisions with other entity names.  Access method names must be unique within a class, but can share the same name as other entities 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 ACCESSOptional end clause to indicate the end of the ACCESS entity

Description

ACCESS declares a special method, called an access method, that is automatically executed each time you access the named instance variable.

 

You can define four types of instance variables in a CLASS declaration.  All of these, except EXPORT, are called non-exported instance variables because they are not directly accessible externally (i.e., outside of the class).

 

For example, if you want to access a non-exported instance variable of an object from a function, you must use a method.  Indeed, this is the purpose of not exporting the variable:  encapsulation by being able to control all references to it through a method.  However, the syntax for referencing a method is obviously different from that of referencing a variable.  This violates encapsulation and is just plain cumbersome, since users of the class must be aware of how a property of the class is implemented in order to know whether to use a functional style or a variable style of reference.

 

For example, note the difference in accessing the instance variables x and y in the function UseClass() when the class uses a regular method for exporting the variable:

 

CLASS Test
 EXPORT x := 100
 INSTANCE y := 10000
 
METHOD GetValueY() CLASS Test
 RETURN y
 
FUNCTION UseClass()
 LOCAL oTest AS Test
 oTest := Test{}
 ? oTest:x
 ? oTest:GetValueY()                // Access y using method

 

If you replace the regular method with an access method, the syntax for accessing both variables is the same even though one of them is insulated by a method:

 

ACCESS y CLASS Test
 RETURN y
 
FUNCTION UseClass()
 LOCAL oTest AS Test
 oTest := Test{}
 ? oTest:x
 ? oTest:y                        // Using ACCESS method

 

Non-exported variables come in three categories, each with its own properties (see the CLASS statement entry in this guide for details):

       INSTANCE

       PROTECT

       HIDDEN

INSTANCE variables are specifically designed to work with access and assign methods which is the main reason for their late binding.  By defining an access method with the same name as an INSTANCE variable, you effectively override the variable by causing all non-assignment references, both external and internal, to invoke the access method.  

 

The exception is that within an access (or assign) method, instance variables of the same name refer to the variable — otherwise, you would never get anywhere.

For example:

 

CLASS Person
  INSTANCE Name, SSN
 
ACCESS Name CLASS Person
  RETURN Name         // Refers to variable Name
 
METHOD ShowName() CLASS Person
  ? Name               // Refers to ACCESS method

You can also use PROTECT and HIDDEN variables in conjunction with access methods.  By defining an access method with the same name as a PROTECT or HIDDEN variable, you can access the variable externally using the same syntax as you would inside the class.  Internal references, however, always refer directly to the variable because of early binding.

 

Of course, you do not have to give the access method and the instance variable the same name.  This is only for your convenience.  It is the return value of the method that is used when you access <idVar>.  Thus, for PROTECT/HIDDEN variables, you can provide an access method with a different name.  For example:

 

CLASS Person
  PROTECT Name_Protected
 
ACCESS Name CLASS Person
  RETURN Name_Protected

A virtual variable is one that is not defined as part of the class but composed from other instance variables.  In other words, it is a variable that is calculated based on the values of other instance variables.  As with non-exported instance variables, you could use a regular method to compute virtual variables, but this means using a different syntax for accessing them.  Access methods extend the syntax used for accessing instance variables to virtual variables.

For example:

 

CLASS Person
  INSTANCE Name, SSN
 
ACCESS Name CLASS Person
  RETURN Name
 
METHOD Init(cName, cSSN) CLASS Person
  Name := cName
  SSN := cSSN
 
ACCESS FullID CLASS Person
  RETURN Name + SSN
 
FUNCTION UseClass()
  LOCAL oFriend AS Person
  oFriend := Person{"Bill Brown", "213-88-9546"}
  ? oFriend:Name         // Bill Brown
  ? oFriend:FullID     // Bill Brown213-88-9546

EXPORT variables are a lot faster and easier to use than non-exported variables and access methods, but using them defies the encapsulation that you should strive for to further the integrity of your application.  Using access and assign methods, you can use exported variables early in the prototyping stage of an application, and later protect the variables with methods without changing the class interface.

 

ACCESS is a special case of METHOD and, except for the way you invoke it (i.e., without arguments, like an instance variable), its behavior is the same as any other method.  See the METHOD statement in this guide for more details.

 

Note: Internal references to access methods that do not have a corresponding regular INSTANCE variable (e.g., virtual variables or public access to HIDDEN or PROTECT variables with different names) must use the SELF:  prefix.  Internal references means references from inside methods of the class or one of its subclasses.  If the system does not find an instance variable, it assumes a memory variable (which can produce a compiler error depending on whether Allow Undeclared Variables has been chosen in the compiler settings), and it does not attempt to identify the reference as an access method, unless SELF:  is used.

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.

 

Examples

The following example uses ACCESS to perform a calculation based on the value of other instance variables:

 

CLASS Rectangle
  INSTANCE Length, Height AS INT
 
METHOD Init(nX, nY) CLASS Rectangle
  Length := nX
  Height := nY
  RETURN SELF
 
ACCESS Area CLASS Rectangle
  RETURN Length * Height
 
FUNCTION FindArea()
  LOCAL oShape AS Rectangle
  oShape := Rectangle{3, 4}
  ? oShape:Area     // Displays:  12

See Also

ASSIGN, CLASS, METHOD, PROPERTY