Getting Information About PowerBuilder Class Definitions

About this chapter

This chapter explains what class definition information is and how it is used, and presents some sample code. Developers of tools and object frameworks can use class definition information for tasks such as producing reports or defining objects with similar characteristics. You do not need to use class definition information if you are building typical business applications.

Overview of class definition information

A ClassDefinition object is a PowerBuilder object that provides information about the class of another PowerBuilder object. You can examine a class in a PowerBuilder library or the class of an instantiated object. By examining the properties of its ClassDefinition object, you can get details about how a class fits in the PowerBuilder object hierarchy.

From the ClassDefinition object, you can discover:

  • The variables, functions, and events defined for the class

  • The class's ancestor

  • The class's parent

  • The class's children (nested classes)

Related objects

The ClassDefinition object is a member of a hierarchy of objects, including the TypeDefinition, VariableDefinition, and ScriptDefinition objects, that provide information about datatypes or about the variables, properties, functions, and event scripts associated with a class definition.

For more information, see the Browser or Objects and Controls.

Definitions for instantiated objects

For each object instance, a ClassDefinition property makes available a ClassDefinition object to describe its definition. The ClassDefinition object does not provide information about the object instance, such as the values of its variables. You get that information by addressing the instance directly.

Definitions for objects in libraries

An object does not have to be instantiated to get class information. For an object in a PowerBuilder library, you can call the FindClassDefinition function to get its ClassDefinition object.

Performance

Class definition objects may seem to add a lot of overhead, but the overhead is incurred only when you refer to the ClassDefinition object. The ClassDefinition object is instantiated only when you call FindClassDefinition or access the ClassDefinition property of a PowerBuilder object. Likewise, for properties of the ClassDefinition object that are themselves ClassDefinition or VariableDefinition objects, the objects are instantiated only when you refer to those properties.

Terminology

The class information includes information about the relationships between objects. These definitions will help you understand what the information means.

object instance

A realization of an object. The instance exists in memory and has values assigned to its properties and variables. Object instances exist only when you run an application.

class

A definition of an object, containing the source code for creating an object instance. When you use PowerBuilder painters and save an object in a PBL, you are creating class definitions for objects. When you run your application, the class is the datatype of object instances based on that class. In PowerBuilder, the term object usually refers to an instance of the object. It sometimes refers to an object's class.

system class

A class defined by PowerBuilder. An object you define in a painter is a descendant of a system class, even when you do not explicitly choose to use inheritance for the object you define.

parent

The object that contains the current object or is connected to the object in a way other than inheritance. This table lists classes of objects and the classes that can be the parents of those objects:

Object

Parent

Window

The window that opened the window.

A window might not have a parent. The parent is determined during execution and is not part of the class definition.

Menu item

The menu item on the prior level in the menu.

The item on the menu bar is the parent of all the items on the associated drop-down menu.

Control on a window

The window.

Control on user object

The user object.

TabPage

The Tab control in which the TabPage is defined or in which it was opened.

ListViewItem or TreeViewItem

The ListView or TreeView control.

Visual user object

The window or user object on which the user object is placed.


child

A class that is contained within another parent class. Also called a nested class. For the types of objects that have a parent and child relationship, see parent.

ancestor

A class from whose definition another object is inherited. See also descendant.

descendant

An object that is inherited from another object and that incorporates the specifics of that object: its properties, functions, events, and variables. The descendant can use these values or override them with new definitions. All objects you define in painters and store in libraries are descendants of PowerBuilder system classes.

inheritance hierarchy

An object and all its ancestors.

collapsed hierarchy

A view of an object class definition that includes information from all the ancestors in the object's inheritance tree, not just items defined at the current level of inheritance.

scalar

A simple datatype that is not an object or an array. For example, Integer, Boolean, Date, Any, and String.

instance variable and property

Built-in properties of PowerBuilder system objects are called properties, but they are treated as instance variables in the class definition information.

Who uses PowerBuilder class definitions

Most business applications do not need to use class definition information. Code that uses class definition information is written by groups that write class libraries, application frameworks, and productivity tools.

Although your application might not include any code that uses class definition information, tools that you use for design, documentation, and class libraries will. These tools examine class definitions for your objects so that they can analyze your application and provide feedback to you.

Scenarios

Class information might be used when developing:

  • A custom object browser

  • A tool that needs to know the objects of an application and their relationships

    The purpose might be to document the application or to provide a logical way to select and work with the objects.

  • A CASE tool that deconstructs PowerBuilder objects, allows the user to redesign them, and reconstructs them

    To do the reconstruction, the CASE tool needs both class definition information and a knowledge of PowerBuilder object source code syntax.

  • A class library in which objects need to determine the class associated with an instantiated object, or a script needs to know the ancestor of an object in order to make assumptions about available methods and variables

Examining a class definition

This section illustrates how to access a class definition object and how to examine its properties to get information about the class, its scripts, and its variables.

Getting a class definition object

To work with class information, you need a class definition object. There are two ways to get a ClassDefinition object containing class definition information.

For an instantiated object in your application

Use its ClassDefinition property.

For example, in a script for a button, this code gets the class definition for the parent window:

ClassDefinition cd_windef
cd_windef = Parent.ClassDefinition

For an object stored in a PBL

Call FindClassDefinition.

For example, in a script for a button, this code gets the class definition for the window named w_genapp_frame from a library on the application's library list:

ClassDefinition cd_windef
cd_windef = FindClassDefinition("w_genapp_frame")

Getting detailed information about the class

This section has code fragments illustrating how to get information from a ClassDefinition object called cd_windef.

For examples of assigning a value to cd_windef, see Getting a class definition object.

Library

The LibraryName property reports the name of the library a class has been loaded from:

s = cd_windef.LibraryName

Ancestor

The Ancestor property reports the name of the class from which this class is inherited. All objects are inherited from PowerBuilder system objects, so the Ancestor property can hold a ClassDefinition object for a PowerBuilder class. The Ancestor property contains a null object reference when the ClassDefinition is for PowerObject, which is the top of the inheritance hierarchy.

This example gets a ClassDefinition object for the ancestor of the class represented by cd_windef:

ClassDefinition cd_ancestorwindef
cd_ancestorwindef = cd_windef.Ancestor

This example gets the ancestor name. Note that this code would cause an error if cd_windef held the definition of PowerObject, because the Ancestor property would be NULL:

ls_name = cd_windef.Ancestor.Name

Use the IsValid function to test that the object is not NULL.

This example walks back up the inheritance hierarchy for the window w_genapp_frame and displays a list of its ancestors in a MultiLineEdit:

string s, lineend
ClassDefinition cd
lineend = "~r~n"

cd = cd_windef
s = "Ancestor tree:" + lineend

DO WHILE IsValid(cd)
   s = s + cd.Name + lineend
   cd = cd.Ancestor
LOOP

mle_1.Text = s

The list might look like this:

Ancestor tree:
w_genapp_frame
window
graphicobject
powerobject

Parent

The ParentClass property of the ClassDefinition object reports the parent (its container) specified in the object's definition:

ClassDefinition cd_parentwindef
cd_parentwindef = cd_windef.ParentClass

If the class has no parent, ParentClass is a null object reference. This example tests that ParentClass is a valid object before checking its Name property:

IF IsValid(cd_windef.ParentClass) THEN
 ls_name = cd_windef.ParentClass.Name
END IF

Nested or child classes

The ClassDefinition object's NestedClassList array holds the classes the object contains.

NestedClassList array includes ancestors and descendants

The NestedClassList array can include classes of ancestor objects. For example, a CommandButton defined on an ancestor window and modified in a descendant window appears twice in the array for the descendant window, once for the window and once for its ancestor.

This script produces a list of the controls and structures defined for the window represented in cd_windef.

string s, lineend
integer li
lineend = "~r~n"

s = s + "Nested classes:" + lineend

FOR li = 1 to UpperBound(cd_windef.NestedClassList)
   s = s + cd_windef.NestedClassList[li].Name &
      + lineend
NEXT
mle_1.Text = s

This script searches the NestedClassList array in the ClassDefinition object cd_windef to find a nested DropDownListBox control:

integer li
ClassDefinition nested_cd

FOR li = 1 to UpperBound(cd_windef.NestedClassList)
		IF cd_windef.NestedClassList[li].DataTypeOf &
      = "dropdownlistbox" THEN
			nested_cd = cd_windef.NestedClassList[li]
      EXIT   
		END IF
NEXT

Class definitions for object instances as distinct from object references

Getting a ClassDefinition object for an instantiated object, such as an ancestor or nested object, does not give you a reference to instances of the parent or child classes. Use standard PowerBuilder programming techniques to get and store references to your instantiated objects.

Getting information about a class's scripts

This section has code fragments illustrating how to get script information from a ClassDefinition object called cd_windef.

For examples of assigning a value to cd_windef, see Getting a class definition object.

List of scripts

The ScriptList array holds ScriptDefinition objects for all the functions and events defined for a class. If a function is overloaded, it will appear in the array more than once with different argument lists. If a function or event has code at more than one level in the hierarchy, it will appear in the array for each coded version.

This example loops through the ScriptList array and builds a list of script names. All objects have a few standard functions, such as ClassName and PostEvent, because all objects are inherited from PowerObject:

string s, lineend
integer li
ScriptDefinition sd
lineend = "~r~n"

FOR li = 1 to UpperBound(cd_windef.ScriptList)
   sd = cd_windef.ScriptList[li]
   s = s + sd.Name + " " + lineend
NEXT
mle_1.Text = s

This example amplifies on the previous one and accesses various properties in the ScriptDefinition object. It reports whether the script is a function or event, whether it is scripted locally, what its return datatype and arguments are, and how the arguments are passed:

string s, lineend
integer li, lis, li_bound
ScriptDefinition sd
lineend = "~r~n"
FOR li = 1 to UpperBound(cd_windef.ScriptList)
   sd = cd_windef.ScriptList[li]
   s = s + sd.Name + " "

   CHOOSE CASE sd.Kind
   CASE ScriptEvent!
      // Events have three relevant properties
      // regarding where code is defined
      s = s + "Event, "
      
      IF sd.IsScripted = TRUE then
         s = s + "scripted, "
      END If
      IF sd.IsLocallyScripted = TRUE THEN
         s = s + "local, "
      END IF
      IF sd.IsLocallyDefined = TRUE THEN
         s = s + "local def,"
      END IF

   CASE ScriptFunction!
      // Functions have one relevant property
      // regarding where code is defined
      s = s + "Function, "
      IF sd.IsLocallyScripted = TRUE THEN
         s = s + "local, "
      END IF
   END CHOOSE

   s = s + "returns " + &
       sd.ReturnType.DataTypeOf + "; "
   s = s + "Args: "

   li_bound = UpperBound(sd.ArgumentList)
   IF li_bound = 0 THEN s = s + "None"

   FOR lis = 1 to li_bound
   CHOOSE CASE sd.ArgumentList[lis]. &
      CallingConvention
      CASE ByReferenceArgument!
      s = s + "REF "
      CASE ByValueArgument!
      s = s + "VAL "
      CASE ReadOnlyArgument!
      s = s + "READONLY "
      CASE ELSE
      s = s + "BUILTIN "
   END CHOOSE

   s = s + sd.ArgumentList[lis].Name + ", "
   NEXT

   s = s + lineend
NEXT
mle_1.text = s

Where the code is in the inheritance hierarchy

You can check the IsLocallyScripted property to find out whether a script has code at the class's own level in the inheritance hierarchy. By walking back up the inheritance hierarchy using the Ancestor property, you can find out where the code is for a script.

This example looks at the scripts for the class associated with the ClassDefinition cd_windef, and if a script's code is defined at this level, the script's name is added to a drop-down list. It also saves the script's position in the ScriptList array in the instance variable ii_localscript_idx. The DropDownListBox is not sorted, so the positions in the list and the array stay in sync:

integer li_pos, li

FOR li = 1 to UpperBound(cd_windef.ScriptList)
   IF cd_windef.ScriptList[li].IsLocallyScripted &
      = TRUE
   THEN
      li_pos = ddlb_localscripts.AddItem( &
         cd_windef.ScriptList[li].Name)
      ii_localscript_idx[li_pos] = li
   END IF
NEXT

Matching function signatures

When a class has overloaded functions, you can call FindMatchingFunction to find out what function is called for a particular argument list.

For an example, see FindMatchingFunction in the PowerScript Reference.

Getting information about variables

This section has code fragments illustrating how to get information about variables from a ClassDefinition object called cd_windef. For examples of assigning a value to cd_windef, see Getting a class definition object.

List of variables

Variables associated with a class are listed in the VariableList array of the ClassDefinition object. When you examine that array, you find not only variables you have defined explicitly but also PowerBuilder object properties and nested objects, which are instance variables.

This example loops through the VariableList array and builds a list of variable names. PowerBuilder properties appear first, followed by nested objects and your own instance and shared variables:

string s, lineend
integer li
VariableDefinition vard
lineend = "~r~n"

FOR li = 1 to UpperBound(cd_windef.VariableList)
   vard = cd_windef.VariableList[li]
   s = s + vard.Name + lineend
NEXT
mle_1.Text = s

Details about variables

This example looks at the properties of each variable in the VariableList array and reports its datatype, cardinality, and whether it is global, shared, or instance. It also checks whether an instance variable overrides an ancestor declaration:

string s
integer li
VariableDefinition vard
lineend = "~r~n"

FOR li = 1 to UpperBound(cd_windef.VariableList)
   vard = cd_windef.VariableList[li]
   s = s + vard.Name + ", "
   s = s + vard.TypeInfo.DataTypeOf

   CHOOSE CASE vard.Cardinality.Cardinality
   CASE ScalarType!
      s = s + ", scalar"
   CASE UnboundedArray!, BoundedArray!
      s = s + ", array"
   END CHOOSE

   CHOOSE CASE vard.Kind
   CASE VariableGlobal!
      s = s + ", global"
   CASE VariableShared!
      s = s + ", shared"
   CASE VariableInstance!
      s = s + ", instance"
      IF vard.OverridesAncestorValue = TRUE THEN
         s = s + ", override"
      END IF
   END CHOOSE
      s = s + lineend
NEXT
mle_1.text = s