CLASS statement
- Last Updated: April 13, 2026
- 24 minute read
- OpenEdge
- Version 12.8
- Documentation
Defines a user-defined class. A class defined with this statement represents a user-defined data type whose characteristics are defined by class members, including a set of class data members and properties that define class data, and a set of class methods and events that define class behavior. In addition to class members, a class definition can include special optional methods (one or more constructors and one destructor). It can also include class-scoped handle-based objects that provide private resources to the class, function prototypes for user-defined functions referenced by the class, and triggers to handle events for widgets and other handle-based objects defined by the class.
You can instantiate a non-abstract class as an object using the NEW function (classes), NEW statement, the New( ) method of the Progress.Lang.Class class, or the DYNAMIC-NEW statement. Instantiating a class returns an object reference that provides access to instance members of the class. You can also access static members of a class without instantiating the class.
.cls) file. For more information, see the Notes section in this reference entry.Syntax
|
- class-type-name
- Defines the type name for a user-defined class type. Specify an ABL
class type name as described in the Type-name syntax reference entry. You can also specify an unqualified class name
(without a package), but only if the class name represents the full type name for the
class (that is, the class is not defined as part of a package).
Note that you cannot specify
Progressas the first component of the package name for any ABL user-defined class. For example,Progress.Inventory.UpdateInvis an invalid type name for a user-defined class and results in a compiler error.The value of class-type-name is restricted to alphanumeric characters plus the symbols
#,$,%,-, and_. - INHERITS super-type-name
- Optionally specifies the type name of a
super class whose state and behavioral characteristics this user-defined class inherits.
The new class becomes a subclass (derived class) of the specified super class and of
every other super class in its class hierarchy. The super-type-name you specify can be an ABL or .NET class type name as
described in the Type-name syntax
reference entry. With an appropriate USING statement, you can also specify an unqualified class name (a class name
without the ABL package or .NET namespace that completes the class type name).
If super-type-name is an abstract class, in this class definition you must implement all the abstract members (properties, methods, and events) that you inherit unless you also define this class as abstract.
The following files must be found at compile time:
- For an ABL super class, the class definition (
.cls) file. - For a .NET super class, the assembly that contains the .NET class definition. OpenEdge places restrictions on the .NET classes you can inherit. For more information on the compilation requirements for inheriting .NET classes, see the Notes of this reference entry.
By default, a class definition inherits directly from the built-in ABL root class,
Progress.Lang.Object. If you inherit from a .NET class, its .NET root class,System.Object, also inherits directly fromProgress.Lang.Object. - For an ABL super class, the class definition (
- IMPLEMENTS interface-type-name [ , interface-type-name]...
- Optionally specifies the type name of one or
more interfaces the new class implements. The new class must implement all properties
and methods defined in the specified interfaces. Specify interface-type-name as an ABL or .NET interface type name as described in
the Type-name syntax reference entry.
With an appropriate USING statement,
you can also specify an unqualified interface name (an interface name without the ABL
package or .NET namespace that completes the interface type name). The value of interface-type-name is restricted to alphanumeric characters
plus the symbols
#,$,%,-, and_.For each interface that you implement, your class must implement all the properties, methods, and class events defined by the interface. If any super class in the hierarchy implements a property, method, or event defined by a specified interface-type-name, this satisfies the requirement to implement that property, method, or event in your class.
If multiple implemented interfaces define an identical member, they all share the same implementation of that member. Thus, ABL classes do not support .NET explicit interface members.
ABL must find the following files at compile time:
- For an ABL interface, the class definition (
.cls) file that contains the interface definition. For more information on defining an ABL interface, see the INTERFACE statement reference entry. - For a .NET interface, the assembly that contains the .NET interface definition. OpenEdge places restrictions on the .NET interfaces you can implement. For more information on the compilation requirements for implementing .NET interfaces, see the Notes of this reference entry.
- For an ABL interface, the class definition (
- USE-WIDGET-POOL
- Directs the
AVM to create an unnamed widget pool that is scoped to the class hierarchy of each
instance of the class. When specified, all dynamic handle-based objects that are created
in the class by and for instance class members are created by default in this unnamed
widget pool. If the class contains static members, this option directs the AVM to create
a separate unnamed widget pool that is scoped to the class for all dynamic handle-based
objects created for or by these static class members in the session.
If methods or externally invoked procedures create their own unnamed widget pools, dynamic handle-based objects are created in the most locally scoped unnamed widget pool, regardless of this option. If no unnamed widget pools are created, either for the class (no
USE-WIDGET-POOLoption specified) or within any invoked procedure or method, all dynamic objects are created by default in the session unnamed widget pool both for instance and static members.Note: When you define an unnamed widget pool in a method or external procedure, it is scoped to that method or procedure. You can delete the widget pool within the method or procedure using theDELETE WIDGET-POOLstatement, or let the AVM delete the widget pool when the method or procedure ends.Within an instantiated class, any class in the class hierarchy that specifies the
USE-WIDGET-POOLdirects the AVM to create one unnamed widget pool that all classes in the class hierarchy share. The AVM deletes this unnamed widget pool when the class instance is deleted (destroyed).You can also define a named widget pool in a class definition file. If you define a named widget pool, object instances are created in that widget pool only if you explicitly reference the widget pool by name.
For more information about defining and using widget-pools, see the CREATE WIDGET-POOL statement reference entry, and for creating widget pools within a class, see Develop Object-oriented ABL Applications.
- ABSTRACT
- Defines the class as
abstract. An abstract class allows you to define any number of instance property,
method, or event members, as abstract. Abstract members are prototypes, similar to
interface members, without an implementation. Abstract members must be implemented by a
derived class to provide data or behavior, but they also function polymorphically in the
class hierarchy wherever they are still defined as abstract. So, for example, an
abstract property can be accessed or an abstract method can be called and the result
depends on its implementation further down in the class hierarchy. Also, whether or not
an abstract class defines abstract members, it must be inherited by a derived class.
Thus, you cannot directly instantiate an abstract class or define an abstract class as
FINAL.An abstract class can inherit from another abstract class or a non-abstract class, and it can redefine any implemented methods that it inherits as abstract. However, it cannot redefine any implemented properties or events that it inherits as abstract. Any redefined abstract methods must, again, be implemented in a derived class.
If a non-abstract class inherits from an abstract class, it must implement all of the inherited abstract members that are not already implemented in the abstract class hierarchy. An abstract class can contain implemented class members, either exclusively or in addition to abstract members. If an immediate subclass of an abstract class does not implement all of its inherited abstract members, the immediate subclass must also be defined as abstract, and a further derived class must implement the remaining abstract members.
- FINAL
- Indicates the class cannot be inherited by
another class. That is, it cannot be used in the
INHERITSphrase in another class definition. Thus, aFINALclass cannot also be defined asABSTRACT. Define a class asFINALwhen you do not want any of its state or behavior overridden. - SERIALIZABLE
- Indicates that object
instances of the class can be:
- serialized to a binary or JSON stream
- passed between an application server and a remote ABL client.
SERIALIZABLE, so using this option on a class that inherits from a non-serializable class will raise a compile-time error. The class types of any data members that are themselves class-based objects must also beSERIALIZABLE. TheSERIALIZABLEoption cannot be used with ABL-extended .NET classes. - class-body
- The body of a class definition is composed of the following types of elements:
- Data members — Class members that define instance or static data (or the state) for the class
- Properties — Class members that define instance or static data, similar to data members, but with the option of associated behavior
- Methods — Class members that define instance or static behavior for the class
- Class events — Class members that define instance or static events for the class
- Constructors — Special methods that define initialization for the class, at least one of which is invoked for the class when an instance (object) is created, and a separate one of which is invoked the first time a class with static members is referenced
- Destructor — A special method that defines finalization behavior and that is invoked when the AVM deletes the object using garbage collection or when you delete the object explicitly
- Class-scoped handle-based objects — Handle-based objects that are not class members, but can be defined in and privately scoped to provide certain resources to the class
- Triggers — ON statements, which are not class members, but can be defined in the class to handle events on class-scoped and other handle-based objects
- User-defined function prototypes — FUNCTION statements that are not class members but declare external user-defined functions referenced by the class
You can define these elements in any order. Only elements that are listed as class members contribute to the type definition of a class. The remaining elements provide weakly typed resources that are privately available to the class definition.
Define elements in the class body using the following syntax:
[ data-member-definitions ] [ property-definitions ] [ method-definitions ] [ event-definitions ] [ constructor-definitions ] [ destructor-definition ] [ class-scoped-definitions ] [ trigger-definitions ] [ udf-prototype-definitions ] END [ CLASS ].- data-member-definitions
- Defines one or more data members of the class. The following
table lists the types of data members you can define and their associated ABL
DEFINEstatement. Data members can be defined as instance or static members. An instance data member is scoped to a particular class instance, while a static data member is scoped to the duration of the ABL session.Table 1. Class data member types Data member type ABL DEFINE statement BUFFER object DEFINE BUFFER statement Class-based object DEFINE VARIABLE statement (with the AS CLASS option, defines a variable as an object reference to a class or interface type) DATASET object DEFINE DATASET statement DATA-SOURCE object DEFINE DATA-SOURCE statement HANDLE DEFINE VARIABLE statement (a primitive type that can reference a handle-based object) Primitive type DEFINE VARIABLE statement (for example, INTEGER or HANDLE) QUERY object DEFINE QUERY statement TEMP-TABLE object DEFINE TEMP-TABLE statement For more information on these data member types, and any class-related restrictions, see the associated ABL
DEFINEstatement reference entry listed in the above table. For more information on accessing data members, see the Class-based data member access reference entry.Note: If the data member is defined in a class that is derived from a .NET class, ABL imposes specific restrictions on the available names you can use to define data members. For more information, see the Notes of this reference entry. - property-definitions
- Defines one or more instance or static property members of the class. If the
class is abstract, an instance property can also be defined as abstract.
Properties are similar to data members with the addition of behavioral and
associated access control options. Like data members, an instance property is
scoped to a particular class instance, while a static property is scoped to the
duration of the ABL session. For more information on defining properties, see the
DEFINE PROPERTY statement reference entry. For more information on accessing properties,
see the Class-based property access reference entry.Note: If the property is defined in a class that is derived from a .NET class, ABL imposes specific restrictions on the available names you can use to define properties. For more information, see the Notes of this reference entry.
- method-definitions
- Defines one or more instance or static method members of the class. If the class
is abstract, an instance method can also be defined as abstract. A method is a
named, callable block of ABL code that can return a value and that you can invoke
like a procedure or a user-defined function (when it returns a value). You can
define multiple overloaded methods with the same name, but with different
parameter lists, and you can define a method that overrides or redefines a method
of the same name and signature that is defined in a super class. Like data members
and properties, an instance method is scoped to a particular class instance and a
static method is scoped to the duration of the ABL session. For more information
on defining methods, see the METHOD statement reference entry. For more information on calling methods, see
the Class-based method call reference entry.Note: If the method is defined in a class that is derived from a .NET class, ABL imposes specific restrictions on the available method names you can use to define methods. For more information, see the Notes of this reference entry.
- event-definitions
- Defines one or more instance or static event members of the class (class events). If the class is abstract, an instance event can also be defined as abstract. A class event allows the defining class to send notifications that some condition has been identified. Like data members, properties, and methods, an instance event is scoped to a particular class instance and a static event is scoped to the duration of the ABL session. For more information on defining class events, see the DEFINE EVENT statement reference entry. For more information on working with class events, see the Class Events Reference.
- constructor-definitions
- Defines one or more constructors for the class. Only one such constructor can be defined as static. An instance constructor is a special method that ABL invokes to initialize data for a new class instance when the object is instantiated using the NEW function (classes), NEW statement, or DYNAMIC-NEW statement. You can define multiple instance constructors distinguished (overloaded) by different parameter lists. You cannot invoke an instance constructor directly except from within the body of another constructor. If you do not define an instance constructor, ABL provides a default instance constructor that takes no parameters. A static constructor is a special method that ABL invokes to initialize static members defined by the class. You can define one static constructor that ABL invokes on the first reference to a class. If you do not define a static constructor, ABL provides a default static constructor. For more information on defining constructors, see the CONSTRUCTOR statement reference entry.
- destructor-definition
- Defines a destructor for the class. You can define only one
destructor for a class. ABL invokes this destructor when the an instance of the
class is deleted, either automatically during garbage collection or manually using
the
DELETE OBJECTstatement. You cannot invoke a destructor directly. If not defined, ABL provides a default destructor. For more information on defining a destructor, see the DESTRUCTOR statement reference entry. - class-scoped-definitions
- Defines class-scoped handle-based objects that are not data
members, but provide certain resources that are privately scoped to the class
definition. These resources include the statically defined widgets that support
the OpenEdge GUI and certain statically defined handle-based objects, all of which
are listed in the following table.
Table 2. Class-scoped handle-based objects Data member type ABL DEFINE statement BROWSE widget DEFINE BROWSE statement BUTTON widget DEFINE BUTTON statement Data stream object DEFINE STREAM statement FRAME widget DEFINE FRAME statement IMAGE widget DEFINE IMAGE statement MENU widget DEFINE MENU statement RECTANGLE widget DEFINE RECTANGLE statement SUB-MENU widget DEFINE SUB-MENU statement WORK-TABLE object DEFINE WORK-TABLE statement For more information on defining these class-scoped objects, and any class-related restrictions, see the associated ABL
DEFINEstatement reference entry. - trigger-definitions
- Defines one or more
ONstatements that specify triggers for events on certain handle-based objects, which can include some of the class-scoped objects listed in the pr. For more information on defining triggers, see the ON statement reference entry. - udf-prototype-definitions
- Declares user-defined function prototypes for functions that are defined external to the class but referenced by methods and triggers defined in the class. For more information on defining user-defined function prototypes, see the FUNCTION statement reference entry.
- END [ CLASS ]
- Specifies the end of the class body definition. You must end the class body definition with the END statement.
Examples
The following samples include three different sets of class and procedure
definitions that provide similar functionality in different ways. Each class defines or
inherits a ProDataSet data member (dsHighCustData) and a
public class method (SetHighCustomerData( )) that
populates the ProDataSet with selected fields in the Sports2020 database from both a Customer
record and related Invoice records, where the Customer has the highest recorded balance in the database and
also has related invoices. Each implementation of SetHighCustomerData( ) also sets two public properties defined by its class
(HighCustBalance and HighCustNum) to the highest database value for Customer.Balance and Customer.CustNum, and
publishes a public class event defined by its class for each Customer record it encounters with related Invoice records. Each class defines or inherits additional data members to
support its own instance of dsHighCustData, and also
defines or inherits a public method (GetHighCustomerData( )) that returns dsHighCustData as an output parameter.
Each of the following sample class files or sets of class files implement this functionality:
-
r-CustObj.cls— Using instance members of anr-CustObjABL class instance -
r-CustObjStatic.cls— Using static members of ther-CustObjStaticABL class type -
r-CustObjAbstractImpl.clsandr-CustObjAbstract.cls— Using instance members of anr-CustObjAbstractImplABL class instance, some of which are abstract members inherited from ther-CustObjAbstractABL abstract class
Each class or set of classes has an associated sample procedure that accesses the respective class and implements a similar application to display data stored by the class.
The following r-CustObj.cls sample class file shows many of the basic features of an ABL class definition. It defines only instance members and is defined as FINAL, meaning that it cannot be inherited by a subclass. This class sample also implicitly inherits from Progress.Lang.Object.
In this class, most of the data members, including the dsHighCustData
ProDataSet and its supporting temp-tables, query, and data-sources, are defined as private,
allowing access to its data primarily through its public properties and methods. However to
demonstrate a public data member, the handle variable for dsHighCustData is
defined as public. The class constructor attaches these data sources to the ProDataSet
temp-table buffers and sets the handle variable (hHighCustData) for
reference by the SetHighCustomerData( ) method to fill and refill the
ProDataSet. (An application might need to call this method multiple times to refill the
ProDataSet as database Customer.Balance values change.)
r-CustObj.cls
|
To access the instance members of this class from outside its class definition, another class or procedure must instantiate the class and assign its object reference to a property or variable whose data type is the instantiated class type, for example:
|
This example uses the NEW statement to instantiate the class. You can also use the NEW function (classes) or New( ) method in an appropriate expression, or the DYNAMIC-NEW statement. You can then reference the public members of the class using the object reference, for example, calling a public instance method of the class:
|
For more information on using object references, see the reference entry for a Class-based object reference.
To access instance members of a class from within the class definition or
a derived class, you can typically reference the member without any prefix, like any local
variable of a procedure or method. However, when the class member has the name of a reserved
keyword, you must prefix the reference with THIS-OBJECT. For more
information, see the reference entry for the THIS-OBJECT system reference.
The following r-CustObjProc.p sample procedure file displays data from
an r-CustObj class instance as follows (with numbers corresponding to the
numbered comments in the sample):
- Defines a static ProDataSet object with a schema that is equivalent to the private
dsHighCustDataProDataSet member defined by ther-CustObjclass - Instantiates the
r-CustObjclass using the NEW statement, assigning its object reference to a variable (rObj) that the procedure uses to access thisr-CustObjinstance and all of its public members - Subscribes its internal procedure,
CustHasInvoices_Handler, as a handler for the publicCustHasInvoicesevent on ther-CustObjinstance - Displays a message showing the default values of the
r-CustObjpublic instance properties,HighCustNumandHighCustBalance - Calls the
SetHighCustomerData( )method on ther-CustObjinstance, which initializes ther-CustObjpublic properties and private ProDataSet and publishes theCustHasInvoicesevent, causing theCustHasInvoices_Handlerprocedure to execute and display a message indicating eachCustomerthat has invoices - Displays a message showing the initialized values of the
r-CustObjpublic instance properties,HighCustNumandHighCustBalance - Calls the
GetHighCustomerData( )method on ther-CustObjinstance to return its private ProDataSet member,dsHighCustData, as an output parameter, and storing the contents in its own equivalent ProDataSet object - Displays the contents of
dsHighCustDatain a down frame, showing fields from theCustomer(ttCust) with the highest stored balance and relatedInvoice(ttInv) fields
r-CustObjProc.p
|
The following r-CustObjStatic.cls sample class file provides functionality similar to r-CustObj.cls, but using static members instead. In addition, the class is not defined as FINAL. So, it can be inherited by an ABL subclass (not shown, here). This sample class also implicitly inherits from Progress.Lang.Object. Note that this class could include instance members as well. However, static members cannot reference instance members of the same class hierarchy; so, any instance members would have to support additional functionality, which could only be accessible using an instance of the class. The supported functionality, using static members, is available only as a function of the class type.
So, in this class, all the members are static. Most of the data members, including the
dsHighCustData ProDataSet and its supporting temp-tables, buffers, query,
and data-sources, are defined as protected, primarily allowing access to its data either by
a subclass or through its public properties and methods from outside the class hierarchy.
However to demonstrate a public data member, the handle variable for
dsHighCustData is defined as public. The static class constructor (like
the constructor in r-CustObj.cls) attaches these data sources to the
ProDataSet temp-table buffers and sets the handle variable (hHighCustData)
for reference by the SetHighCustomerData( ) to fill and refill the
ProDataSet.
As another difference from r-CustObj.cls, note the use of the
alternate static buffers (bHighCust, bCustomer, and
bInvoice), which allow other static members, such as the static query and
method members, to access the database Customer and
Invoice tables. The default buffers of database tables cannot be accessed
from a static class member because ABL treats these buffers implicitly as instance members
of the same class.
r-CustObjStatic.cls
|
To access the static members of this class from outside of its class definition (and any derived class), you do not need to instantiate the class. You only need to reference the member using static type-name syntax, for example:
|
For more information on static type-name syntax, see the Type-name syntax, Class-based data member access, Class-based method call, and Class-based property access reference entries.
To access static members of a class from within the class definition or a derived class, you can typically reference the member without any prefix, like any local variable of a procedure or method. However, when the class member has the name of a reserved keyword, you must prefix the reference using static type-name syntax.
The following r-CustObjStaticProc.p sample procedure file displays
static data from the r-CustObjStatic class type in a manner similar to how
r-CustObjProc.p displays instance data from an
r-CustObj class instance, except all references to public members are
through the class type (r-CustObjStatic) instead of through an object
reference (rObj in r-CustObjProc.p). Thus,
r-CustObjStaticProc.p has no need to instantiate
r-CustObjStatic. Otherwise, the application is exactly the same.
r-CustObjStaticProc.p
|
The following sample class files, r-CustObjAbstract.cls and
r-CustObjAbstractImpl.cls, provide functionality similar to
r-CustObj.cls, but using a combination of abstract and non-abstract
instance members that are defined in the abstract class, r-CustObjAbstract,
and inherited by the non-abstract class, r-CustObjAbstractImpl.
The r-CustObjAbstract.cls class file defines the
r-CustObjAbstract abstract class. Its abstract members consist of most of
the public members of the class, including properties, methods, and the class event. This
class also implicitly inherits from Progress.Lang.Object.
In this class, all the data members (which are always non-abstract), including the
dsHighCustData ProDataSet and its supporting handle variable,
temp-tables, buffers, query, and data-sources, are defined as protected, allowing direct
access to its data from any subclass that inherits from it or through its public properties
and methods (once implemented) from outside the class hierarchy. The abstract class
constructor (like the constructor in r-CustObj.cls) attaches the data
sources to the ProDataSet temp-table buffers and sets the handle variable
(hHighCustData) for reference by the subclass that implements the
abstract SetHighCustomerData( ) method to fill and refill the ProDataSet.
This constructor also subscribes a private method
(CustHasInvoices_Handler( )) as a handler for the abstract
CustHasInvoices event. This handler thus always responds to the event, no
matter how it is implemented. Note that the class cannot publish the event, because it has
not yet been implemented.
One public method, GetHighCustomerData( ), is implemented (not abstract)
because its only function is to return dsHighCustData as an output
parameter. If necessary, an abstract subclass can still override it again as abstract for
implementation further down the class hierarchy, or it can simply be overridden by any
subclass. The abstract method, SetHighCustomerData( ), is intended to be
implemented any number of ways. For example, an alternative implementation could accumulate
an actual Customer balance from related Invoice.Amount
values instead of using the stored value of Customer.Balance, which does
not necessarily match this total. For an example of this implementation, see the
r-ICustObjectImpl2.cls sample class file, which is described in the
Examples section of the INTERFACE statement reference entry.
Also, note the use of the protected alternate buffers (bCustomer and
bInvoice). These buffers allow access to the database
Customer and Invoice tables by certain protected class
member definitions, including the ProDataSet query and data-sources, that cannot reference
the default buffers of database tables. ABL implicitly treats the default buffers of
database tables as private instance members of any class that references them; so they
cannot be inherited along with any protected member definitions where they might be
included. As such, the protected buffers allow any derived class to access the same buffers
that are referenced in the protected member definitions it inherits.
r-CustObjAbstract.cls
|
The r-CustObjAbstractImpl.cls class file defines the non-abstract
r-CustObjAbstractImpl class, which inherits
r-CustObjAbstract and implements its abstract members. The class is not
defined as FINAL. So, it can be inherited by an ABL subclass (not shown, here).
The abstract member implementations include initial values for the
HighCustBalance and HighCustNum properties, the
CustHasInvoices event so it can be published, and the
SetHighCustomerData( ) method, which is implemented almost exactly the
same as for r-CustObj, to set these properties, fill the ProDataSet, and
publish the event when appropriate.
r-CustObjAbstractImpl.cls
|
Note that from within r-CustObjAbstractImpl, members inherited from r-CustObjAbstract (such as hHighCustData and
HighCustBalance) are accessed without any prefix, as if
they were defined in the same class. You can access any inherited member of a super class
this way. However, if an inherited instance member has the name of a reserved keyword, you
must prefix the member reference with THIS-OBJECT. For more information,
see the reference entry for the THIS-OBJECT system reference. For an inherited static
member named with a reserved keyword, you must use static type-name syntax as previously
described for the r-CustObjStatic class.
The following r-CustObjAbstractProc.p sample procedure file displays
data from an instance of r-CustObjAbstractImpl in a manner similar to how
r-CustObjProc.p displays data from an instance of
r-CustObj. The only difference is in the event handler procedure
(CustHasInvoices_Handler) which responds to the
CustHasInvoice event in way that works more smoothly with the event
handler provided by the r-CustObjAbstract class. Otherwise, the application
is exactly the same.
r-CustObjAbstractProc.p
|
For an example of an ABL class that inherits from a .NET class, see the WAIT-FOR statement (.NET and ABL) reference entry.
Notes
- You can terminate a CLASS statement with either a period (.) or a colon (:), but typically use a colon (:).
- A class definition (
.cls) file can contain only one class definition that is optionally preceded by one or moreUSINGstatements, aBLOCK-LEVEL ON ERROR UNDO, THROWstatement, or aROUTINE-LEVEL ON ERROR UNDO, THROWstatement. The complete class definition must begin with theCLASSstatement and end with theENDstatement, and theCLASSstatement must be the first compilable statement after anyUSING.BLOCK-LEVEL ON ERROR UNDO, THROW, orON ERROR UNDO, THROWstatements in the file. A class definition file containing a class definition cannot also contain an interface definition. - The access mode for a class definition is always
PUBLIC. - In effect, a user-defined class represents a unique data type. In ABL, you can use a class type much as you would any ABL built-in data type. You can define variables, parameters, return types, and class-based properties as a class type. These data elements can then hold a reference to a class instance (object reference). You can also assign an object reference to a temp-table field defined as the Progress.Lang.Object class type; but you cannot assign an object reference to a database table field. You can use the object reference to a class to access PUBLIC instance members of that class. For more information on object references, see the reference entry for a Class-based object reference. You can also use a class type name to access available static members of that class, whether or not an instance of the class exists. For more information on using class type names to access static class members, see the Class-based data member access, Class-based method call, Class-based property access, and Type-name syntax reference entries.
- The class name part of class-type-name can be an ABL reserved keyword (such as Display). If it is a reserved keyword, note that ABL does not fully support user-defined class names that are identical to reserved keywords. For more information, see the Type-name syntax reference entry.
- You can reference include files from within a class definition file. For more information about include files, see the reference entry for an { } Include file reference.
- All built-in preprocessor directives are supported in class definition files.
- All built-in preprocessor names are supported in class definition files. For a list of preprocessor names, see the reference entry for an { } Preprocessor name reference.
- You cannot pass compile-time arguments to class definition files. However, you can pass compile-time arguments to include files referenced in a class definition file.
- The compiled version of a class definition file is an r-code (
.r) file. For more information, see the COMPILE statement reference entry. - You cannot run r-code compiled for a class definition file with the
RUNstatement. - Non-
PRIVATEdata members and properties within a class definition (.cls) file maintain their characteristics throughout the inherited class hierarchy. Thus, you cannot override non-PRIVATEdata members and properties in a subclass that are defined in a super class. In other words, you cannot define a data member or property in a subclass using the same name as a non-PRIVATEdata member or property defined in one of its super classes. - You can create an instance of a class using the
NEWfunction, theNew( )method of theProgress.Lang.Classclass, theNEWstatement, or theDYNAMIC-NEWstatement, and assign the object reference returned for that instance as the value of a data element defined to reference instances of that class type. You can access an object instance, as well as itsPUBLICinstance data members, properties, and methods, using its associated object reference.PACKAGE-PROTECTEDandPACKAGE-PRIVATEinstance data members, properties, and methods can be accessed by objects within the same package as the object instance. For more information on instantiating classes as objects, see the CONSTRUCTOR statement, NEW function (classes), New( ) method of the Progress.Lang.Class class, NEW statement, or DYNAMIC-NEW statement reference entries. For more information on referencing class instances, see the Class-based object reference entry. - The static members of a class are initialized with the first reference to its class type and just prior to execution of its static constructor, whether or not the class is instantiated in the process. These members remain in ABL session memory until the session ends or until the defining class is recompiled. Note that static data members and properties are not constant; the values of static data members can be changed like any data member, and the values of static properties can be changed as provided by the property definition. For more information on static member initialization, see the CONSTRUCTOR statement reference entry.
- ABL provides a system reference for the currently running instance of
this class, called
THIS-OBJECT. For more information, see the reference entry for the THIS-OBJECT system reference. - If this class is a subclass of some super class, you can use the
SUPERsystem reference within a class instance to access thePUBLIC,PACKAGE-PROTECTED, andPROTECTEDinstance methods of all super classes within the inherited class hierarchy. For more information, see the reference entry for the SUPER system reference. You can also use static type-name syntax to access any static method that you redefine (override) in the class hierarchy. For more information, see the Type-name syntax reference entry. - You can store class definition r-code files in ABL libraries (procedure libraries (.pl) and archive files (.apl)). If the AVM encounters a library on the PROPATH, it will search the library for the specified r-code. However, you cannot execute r-code files stored in a library that is not on PROPATH using the library-path<<member-name>> syntax.
- You cannot define a
NEW SHAREDorNEW GLOBAL SHAREDvariable in a class definition (.cls) file. - You cannot use ActiveX controls within a class definition (.
cls) file. However, you can use COM automation objects within a class definition (.cls) file, with any event handlers for a COM object defined in a procedure file. - For more information on class definition (
.cls) files, see Develop Object-oriented ABL Applications. - If you inherit a .NET class, implement a .NET interface, or otherwise access a .NET object type in a class definition, ABL must find the assembly that defines the .NET object type at compile time. For information on how ABL locates and identifies .NET object types, see the Type-name syntax reference entry.
- Although you can override the .NET
WndProc( )method, doing so can be risky. The method will be called for every event, likeWM_MOUSEMOVEandWM_PAINT, so it could be called thousands of times for a single form, causing performance issues. It can also be called at unexpected times and cause unexpected behavior. Overriding WndProc when using ABL embedded windows with .NET forms could be especially problematic. See Develop Object-oriented ABL Applications for more information. - If you inherit a .NET class, the
GetType( )instance method (inherited fromSystem.Object)returns incomplete information for the ABL part of the object. - If you inherit a .NET class, you cannot:
- Override the .NET Dispose( ) or Finalize( ) method
- Define a method with certain reserved method names
For more information, see the METHOD statement reference entry.
- You cannot:
- Inherit from a .NET class that is, itself, defined with any of the following .NET
directives (as specified in C#):
-
internal -
private -
sealed -
static
-
- Define an ABL class that can become an additional part for a .NET
partialclass - Inherit from a .NET abstract class that defines an abstract indexed property
- Inherit from a .NET generic class
- Inherit from the following .NET class types or any class types that are derived from
them:
-
System.Delegate -
System.Enum -
System.Threading.Thread -
System.ValueType
-
- Implement a .NET interface that:
- .NET defines as
privateorinternal(as specified in C#) - Is generic or that defines a generic method prototype
- Defines an indexed property prototype (including a default indexed property)
- .NET defines as
- Inherit from a .NET class that is, itself, defined with any of the following .NET
directives (as specified in C#):
See also
Assignment (=) statement, BLOCK-LEVEL ON ERROR UNDO, THROW statement, Class-based object reference, CONSTRUCTOR statement, DEFINE EVENT statement, DEFINE PROPERTY statement, DEFINE VARIABLE statement, DESTRUCTOR statement, DYNAMIC-NEW statement, FUNCTION statement, INTERFACE statement, METHOD statement, NEW function (classes), New( ) method, NEW statement, ON statement, ROUTINE-LEVEL ON ERROR UNDO, THROW statement, Statements defining other class elements as specified in Table 1 and Table 2, Type-name syntax, USING statement, VAR statement