Access Control and the Declaration of Protected Properties and Methods

Application class objects have private and public access control. Properties or methods that are declared outside the “private” declaration section have public access control. This means that they can be referenced and used by any PeopleCode. This access is of course subject to access controls such as “readonly”. Private properties and methods are private to the class, not instance, and can only be referenced by objects of this application class.

Between these two access control schemes of public and private, lies the concept of protected methods and properties. Protected methods and properties can be accessed only by objects of this application class and those derived from this application class. Use protected methods or properties when you want to hide them from outside use, but allow the flexibility of using them in derived classes.

The declarations of protected variables and methods are done within the class declaration, before the declaration of private variables and methods. You can use protected instance variables in interface classes. Protected methods and properties can be overridden by subclasses.

Most of the time your design can be implemented through the use of private methods and properties without resorting to the use of protected methods and properties. The following examples demonstrates the rules and some of the subtleties about when to use protected methods and properties.

class A; 
   method A(); 
   property string Q; 
protected 
   method MP() Returns string; 
   property string p; 
end-class; 

method A; 
   &p = "Class A: property p"; 
end-method; 

method MP 
   /+ Returns String +/ 
   Return "Class A: method MP"; 
end-method; 

==================== 

class B extends A; 
   method B(); 
   method M(&X As C); 
   method m2(&Aobj As A); 
   /* property string P; */ 
protected 
   property string Q; 
   method MP() Returns string; 
end-class; 

method B; 
   %Super = (create A()); 
   &Q = "Class B: property Q"; 
   /* &P = "Class B: property P";*/ 
end-method; 

method M 
/+ &X as FOXTEST:C +/; 

   MessageBox(0, "", 0, 0, "In B:M %This.P=" | %This.p); 
/* %This.p is class A property P */
   MessageBox(0, "", 0, 0, "In B:M %This.Q=" | %This.Q); 
/* %This.q is class B property Q */
   MessageBox(0, "", 0, 0, %This.MP()); 
/* %This.MP() calls class B method MP */

   if &X.p = "Error" then 
   end-if;
/* error: cannot reference &X.p since class B is 
not involved in the implementation of class C */
end-method;

method m2 
   /+ &Aobj as FOXTEST:A +/ 
/* MessageBox(0, "", 0, 0, "In B:M2 &Aobj.P=" | &Aobj.p); 
/* Error: cannot reference &Aobj.p from class B 
since class B is not involved in its implementation */

end-method;

method MP 
   /+ Returns String +/ 
   Return "Class B: method MP"; 
end-method; 

======================= 

class C extends A; 
   method C(); 
protected 
   property string P; 
end-class; 

method C; 
   %Super = (create A()); 
   &P = "Class C: property P"; 
end-method; 
========================== 

/* AE program */ 
import FOXTEST:*; 

Local A &A = (create A()); 

Local object &obj = &A; 
MessageBox(0, "", 0, 0, "In AEMINITEST: &Obj.p=" | &obj.P); 
/* run time error: anonymous access through type 
object not allowed*/

The following example also illustrates some of the rules surrounding protected access control.

import FOXTEST:Point3d;

class Point
   method Point(&X1 As integer, &Y1 As integer);
   method Warp(&A As Point3d);
protected
   property integer x;
   property integer y;
end-class;

method Point
   /+ &X1 as Integer, +/
   /+ &Y1 as Integer +/;
   %This.x = &X1;
   %This.y = &Y1;
end-method;

method Warp
   /+ &A as FOXTEST:Point3d +/
   /* Local Integer &temp = &A.Z;  ERROR cannot access &A.Z */
end-method;
================================
import FOXTEST:Point;

class Point3d extends Point
   method Point3d(&X1 As integer, &Y1 As integer, &Z1 As integer);
   method Delta(&P As Point);
   method Delta3d(&Q As Point3d);
protected
   property integer z;
end-class;

method Point3d
   /+ &X1 as Integer, +/
   /+ &Y1 as Integer, +/
   /+ &Z1 as Integer +/;
   %Super = (create Point(&X1, &Y1));
   %This.z = &Z1;
end-method;

method Delta
   /+ &P as FOXTEST:Point +/

/* &P.x = %This.x; 
ERROR cannot access &P.x since while Point3d 
(the class in which references to fields x and y occur) 
is a subclass of Point (the class in which x and y are declared), 
it is not involved in the implementation of Point (the type of parameter p)*/

/* &P.y = %This.y; 
ERROR cannot access &P.y. Same reason as above */
end-method;

method Delta3d
   /+ &Q as FOXTEST:Point3d +/

/* The protected members of Q can be accessed because the class point3d is a⇒
 subclass of Point and is involved in the implementation of Point3d */
   &Q.x = %This.x; 
   &Q.y = %This.y;
   &Q.z = %This.z;
end-method;