Specifies the name of an ABL or .NET data type that you can specify as a single instance or as an array of such instances. Thus, an ABL data type can be a built-in primitive type or an array of such primitive types, or it can be a class-based built-in or user-defined object type (such as a class, enumeration, or interface type) or an ABL array of such object types. A .NET data type can only be a class-based object type (such as a class, structure, enumeration, or interface) or an ABL array of such object types. The EXTENT option, used to define an array of types, is thus counted as part of the array type name.
An unquoted string that specifies the name of a built-in ABL primitive type. For information on the supported primitive types and their names, see the Data types reference entry.
object-type-name
Specifies an ABL or .NET object type using the following syntax:
An ABL object type, where ABL-object-type consists of text elements with the following syntax:
[ package-name . ]class-interface-or-enum-name
package-name
A period-separated list of text components that, along with class-interface-or-enum-name, uniquely identify an ABL class, interface, or enum. These text components specify a package that is based on a valid directory pathname, relative to PROPATH, which identifies the location of the file that defines the class, interface, or enum. Thus, each text component of package-name maps to a directory level in the path, and each slash separator in the path corresponds to a period separating two components.
If specified, the relative path of the class definition file represented by package-name must remain constant between compile time and run time. If the class definition file resides directly on PROPATH, the class or interface is not defined in a package and therefore has no package-name in its type name.
With the presence of an appropriate USING statement you can also specify an ABL object type that is defined in a package using the class-interface-or-enum-name without its qualifying package-name. For more information, see the notes for this reference entry.
class-interface-or-enum-name
The name of an ABL class, interface, or enumeration. This name must match the name of a class definition file (excluding the .cls or .r extension) located in the relative path represented by package-name, if specified. The name must begin with an alphabetic character and it cannot contain a period or a space.
If the ABL-object-type has a package-name that contains embedded spaces, you must enclose the entire ABL-object-type in quotes ("). Otherwise, quotes are optional.
Note: Do not place a class definition file in a directory whose name contains a period (.) character; ABL interprets the component after the period as another directory level and will therefore not find the referenced class definition file.
[ " ]dotNET-object-type[ " ]
A .NET object type, where dotNET-object-type consists of text elements with the following syntax:
[namespace . ]dotNET-object-name [ + inner-name ]
namespace
A period-separated list of text components that, along with dotNET-object-name, uniquely identify a .NET type. The components of namespace are defined according to .NET requirements. ABL does not support access to .NET types defined in the default namespace. In other words, you cannot access a .NET type that does not have a namespace defined for it.
However, with the presence of an appropriate USING statement, you can also specify a .NET object type using the dotNET-object-name without its qualifying namespace. For more information, see the notes for this reference entry.
dotNET-object-name
The name of a .NET class (including a structure or enumeration), delegate, interface, or other object type referenced within the .NET namespace specified by namespace.
inner-name
The name of a .NET nested (inner) type defined within the .NET type definition specified by namespace.dotNET-object-name. Thus, inner-name can represent the name of an:
Inner class defined by the specified .NET class
Inner enumeration defined by the specified .NET class
Inner interface defined by the specified .NET interface
Caution: .NET languages normally separate the name of an inner type from the defining type name using a period (.). You must replace this period with a plus sign (+) to reference the inner type name in ABL.
If the name part of the dotNET-object-type contains any embedded spaces, square brackets ([]), or angle brackets (<>) you must enclose the entire dotNET-object-type in quotes ("). Otherwise, quotes are optional.
For more information on defining object types in ABL, see the CLASS statement or the INTERFACE statement reference entry, depending on the type of class-based object.
EXTENT [constant ]
EXTENT indicates that it is an array of the specified type and constant is an integer value that specifies the number of elements in the array. Without constant, the array is an indeterminate array type.
If your PROPATH is "C:/myfiles", and your class definition file name is "C:/myfiles/acme/myObjs/CustObjs.cls", then ABL requires package-name to be "acme.myObjs." and class-or-interface-name to be "CustObjs".
The .NET Button class is in the System.Windows.Forms namespace. Therefore, you reference its qualified (complete) type name like this:
System.Windows.Forms.Button
The .NET ControlCollection class is an inner class of System.Windows.Forms.Control. Therefore, you reference its qualified type name like this:
System.Windows.Forms.Control+ControlCollection
The following code fragment defines object references to the .NET type, System.Drawing.Point, and to a one-dimensional .NET array of System.Drawing.Point elements:
DEFINE VARIABLE rPoint AS CLASS System.Drawing.Point NO-UNDO.
DEFINE VARIABLE rPointArray AS CLASS "System.Drawing.Point[]" NO-UNDO.
Notes
Both elements of an ABL object type name (package-name and class-interface-or-enum-name) must conform to the case sensitivity requirements of the operating system (e.g., UNIX or Windows). On a case-sensitive OS, only the first reference to the object type name must be case correct. ABL follows this initial letter case for all subsequent references to the type.
You cannot specify Progress as the first component of package-name for any ABL user-defined class. For example, Progress.Inventory.UpdateInv is an invalid type name for a user-defined class and results in a compiler error.
You must use a class type name (static type-name syntax) to qualify all references to the following static members of an ABL class:
All PUBLIC static members that you reference from outside the defining class context.
All PUBLIC, PROTECTED, or PRIVATE static methods, properties, events or variable data members that you reference from inside the defining class context whose names are identical to a reserved keyword.
PUBLIC or PROTECTED static methods that are overridden in the current class definition in order to call the specific method definition in a super class. If you do not use static type-name syntax to call an overridden static method, the method definition at the nearest point in the class hierarchy, starting with the current class, is called.
You must also use equivalent static type-name syntax to reference static members of a class whose names are identical to reserved keywords, as well as from inside the ABL class hierarchy, including when you call event methods on inherited static class events.
ABL allows you to name an ABL class or interface using an ABL reserved keyword, such as Display or DISPLAY. For a list of ABL reserved keywords, see the Keyword Index. However, this is not a recommended coding practice, in part because ABL does not fully support the use of static type-name syntax for a class or interface name that is an ABL reserved keyword. This limitation is mitigated if the type name is a fully qualified type name that includes both the package-name and class name.
Depending on the type definition, the context of the type reference, and the presence of an appropriate USING statement, you can use a qualified or an unqualified class, interface, or enum name to reference an ABL object type. A qualified type name is one that includes both a package-name and a class-interface-or-enum-name. An unqualified type name is one that includes class-interface-or-enum-name alone, without a package-name. All qualified type names must be fully qualified, using a complete package-name. ABL does not support partially qualified type names using a partial package-name specification. Without an appropriate USING statement, you can only specify an unqualified type name when the type is defined directly on PROPATH (not in a package). In this case, the unqualified type name is the complete type name for the object type.
Note: For classes with static members, Progress Software Corporation recommends that you either define the class in a package-name and always reference its static members using the fully qualified class type name, or use a naming convention that defines static members with unique names.
Depending on the presence of an appropriate USING statement, you can use a qualified or unqualified type name to reference a .NET type. A qualified .NET type name is one that includes both a namespace and a dotNET-object-name. An unqualified .NET type name is one that includes dotNET-object-name alone, without its defined namespace. All qualified .NET type names must be fully qualified, using a complete namespace. ABL (unlike .NET languages) does not support partially qualified type names using a partial namespace specification. Without an appropriate USING statement, you cannot specify an unqualified .NET type name, because ABL does not support access to .NET types that are defined in the .NET default namespace.
When you specify the type name of a class, interface, or enumeration in its ABL type definition statement (CLASS, INTERFACE, or ENUM statement), and the class file where the type is defined resides in a package directory, you must specify the qualified type name (package-name.class-interface-or-enum-name) for its definition, even with the presence of an appropriate USING statement. You can only specify an unqualified type name (class-interface-or-enum-name alone) in its type definition statement when the class file defining the type resides directly on PROPATH (is not in a package directory).
ABL allows a locally scoped name (for example, a variable, temp-table, buffer name) to be identical to the name of an accessible class. If this is the case, the locally scoped name takes precedence over any static type-name reference to the unqualified class type name, causing a compiler error on any such reference to a static class member. To avoid this error, ensure that no locally scoped names have the same name as the class, and always either use fully qualified type-name syntax to reference the static class member or use naming conventions to guarantee uniqueness for static member names.
Because of the similarity between the syntax of object-type-name references and table buffer and field references (including similarities between syntax type-name references and field attribute references), ABL can encounter ambiguous references among them, resulting in compilation errors. To ensure that ABL always recognizes object-type-name references unambiguously, either define all object type names with at least three period (.) separators (in other words, at least three components in any package-name specification) or use naming conventions to guarantee that object-type-name references and database element references are unique. Otherwise, ABL recognizes all such references as object-type-name references.
For example, suppose that you have a user-defined class type in your PROPATH, Sports2000.Customer.Name, which defines a static property, Label. The reference in the following code fragment would then be ambiguous because ABL cannot distinguish between a reference to this static Label property and a reference to the LABEL attribute on the fill-in widget that is defined for the Name field in the Customer table of the Sports2000 database:
DEFINE VARIABLE cLabel AS CHARACTER NO-UNDO.
DEFINE FRAME a Sports2000.Customer.Name.
FIND FIRST Sports2000.Customer.
cLabel = Sports2000.Customer.Name:Label. /* Ambiguous reference */
For more information on the types provided by Microsoft .NET, see the .NET class library documentation available from the Microsoft® Development Network (MSDN) at http://msdn.microsoft.com/en-us/library/aa338209.aspx.
Note: The .NET class library does not list nested types as members (which they are) of the type that defines them. Instead, it lists each nested type definition immediately following the type that defines it. You can identify .NET nested types in this listing by the period (.) that separates the inner-name of the nested type name from the name of the .NET type that defines it. As shown in this syntax and examples, ABL uses a plus (+) instead of a period (.) to reference the inner-name of a nested type.
To compile ABL references to a .NET type, the type must be defined in either an automatically-loaded .NET assembly or in a .NET assembly that is listed in an OpenEdge® assembly references file named assemblies.xml. This file must be available either in the working directory or in the directory specified by the Assemblies (-assemblies) startup parameter. You must also deploy this file at run time. For more information on working with assembly references files, see OpenEdge Development: GUI for .NET Programming. OpenEdge also loads the following assemblies automatically if they are not referenced in assemblies.xml:
Progress.NetUI.dll — Assembly where all custom OpenEdge .NET classes and interfaces reside
Mscorlib.dll — Assembly where all core Microsoft .NET classes and interfaces reside
System.Windows.Forms.dll — Assembly where all Microsoft form and control classes and interfaces reside
System.Drawing.dll — Assembly where basic Microsoft graphics classes and interfaces reside
The point at which OpenEdge loads any .NET assemblies depends on your application (see the following note on loading the CLR).
OpenEdge loads the .NET Common Language Runtime (CLR) and all required assemblies for access by ABL if any of the following conditions exists:
You use the Preload CLR (-preloadCLR) startup parameter to start the current ABL session, which causes the .NET CLR to load at session startup.
The ABL compiler encounters a reference to a qualified object type name, and either that type name matches (or results from a match) to a USING statement containing the FROM ASSEMBLY option or the type cannot be found on PROPATH (meaning that ABL assumes it is a .NET type). This reference can occur on any ABL statement where a type name is used, such as a DEFINE VARIABLE, CAST, static method call, and so on.
An unqualified type name that does not resolve to a qualified type name from a USING statement match is assumed to be the name of an ABL user-defined type, which does not cause the CLR to load.
At run time, the ABL Virtual Machine (AVM) executes a statement using the NEW function (classes) for a .NET object.
At run time, the AVM accesses a static .NET method, property, or data member.
When you first reference a .NET type in a procedure or class file (compilable unit), ABL is always case-sensitive when using your reference to identify and search for the type definition. However, for names of .NET class members, including properties, data members, methods, and enumeration members, ABL is case insensitive.
Note: Microsoft recommends that .NET names never be distinguished by letter case, alone. However, if a .NET class does have two class members with names distinguished only by letter case, ABL finds only the first one defined in the class.
For information on how ABL maps .NET types to ABL primitive types, see the Data types reference entry.
When creating and accessing .NET arrays in ABL, you must use methods of the .NET System.Array type. ABL also supports automatic mappings between ABL and one-dimensional .NET arrays, allowing supported .NET and ABL arrays to be assigned to each other or passed to each other as routine parameters. For more information, see the Data types reference entry.
Note that you can specify an ABL array of .NET array objects, which is equivalent to a two-dimensional array. The following example defines an ABL array with 10 elements, each of which can reference a one-dimensional .NET array of System.Drawing.Point objects:
DEFINE VARIABLE rPointArray AS CLASS "System.Drawing.Point[]" EXTENT 10 NO-UNDO.
You can also specify a constructed .NET generic type for dotNET-object-name. ABL supports references to a .NET generic type for all uses of .NET types except to specify a .NET class to inherit or a .NET interface to implement in an ABL class definition. For more information on constructing and using .NET generic types in ABL, see the Data types reference entry.