From: Rony G. F. <Ron...@wu...> - 2009-09-29 09:55:09
|
In the context of an assignment for a student (creating a frameword for vCalendar and vCard) the following concept has been developed: * create a root class with a class attribute "attr" and "values" which both will get array values from subclasses, that determine the attributes which should be created for the subclasses (using the 'define' method) in this class' class constructor, * create for each vCard type a subclass with a class constructor, that first assigns array objects to the root class' class attributes "attr" and "values" which denote the attribute names which this class instances should have. The problem: * 'self' in class methods is not set to the class object for which a class method executes, as is the case for 'self' in instance methods. Rather 'self' will refer to the class object for which the class method got defined. Because of this it is not possible to create the attributes dynamically in the root class class constructor! A stripped down example program from that student, sketching the problem: /* b2.rex */ say "-"~copies(50) L = .LIST~OF(.ADR) DO CLZ OVER L SAY "Defined methods for instances of" pp(CLZ)":" DO IDX OVER CLZ~METHODS(clz)~ALLINDEXES~SORT SAY pp(IDX) END SAY "-------" END /* ---------------------------------------------------------------- CLASS DEFINITION OF VCARD VERSION 3.0 */ ::CLASS VCARD30 PUBLIC ::ATTRIBUTE ATTR CLASS --ATTRIBUTE USED IN SUBCLASSES /* INIT METHOD THAT CREATES MAKER AND SETTER METHODS FOR ATTRIBUTES */ ::METHOD INIT CLASS ; --TRACE ?I say "VCARD30::"self": INIT CLASS, self~attr="pp(self~attr) if \self~attr~isA(.array) then return say "VCARD30::"self": defining ATTR-attributes:" -- create attributes (getter and setter methods) for instances DO NAME OVER SELF~ATTR say "... defining:" pp(name) pp(name"=") SELF~DEFINE(NAME, MAKEGETTER(NAME)) SELF~DEFINE(NAME||'=', MAKESETTER(NAME)) END ::METHOD INIT --TRACE ?I ATTR = SELF~CLASS~ATTR --ASSIGNS NEWLY CREATED ATTRIBUTES VALUES = SELF~CLASS~VALUES DO NAME OVER ATTR SELF~SEND(NAME||"=",.ARRAY~NEW) --SETS INITIAL ATTRIBUTE-VALUES TO AN ARRAY END /* ---------------------------------------------------------------- CLASS DEFINITION OF ADR FURTHER DETAILS RFC 2426, P. 11, 31 */ ::CLASS ADR PUBLIC SUBCLASS VCARD30 ::METHOD INIT CLASS say pp("ADR::"self)": INIT CLASS, top: self~attr="pp(self~attr) /* ATTRIBUTE AND VALUE VARIABLES OF CLASS */ --TRACE ?I SELF~ATTR = .ARRAY~OF("TYPE", "TEST_ATTRIBUTE") say pp("ADR::"self)": INIT CLASS, bottom: self~attr="pp(self~attr) FORWARD TO (SUPER) ::METHOD INIT --TRACE ?I FORWARD TO (SUPER) CONTINUE /* ================================== routines ================================= */ /* enclose argument's string value in square brackets */ ::routine pp parse arg val return "["val"]" /* ROUTINE CREATES A GETTER METHOD FOR ATTRIBUTES */ ::ROUTINE MAKEGETTER PARSE ARG NAME CODE="EXPOSE" NAME "; RETURN" QUOTE(NAME) RETURN CODE /* ROUTINE CREATES A SETTER METHOD FOR ATTRIBUTES */ ::ROUTINE MAKESETTER PARSE ARG NAME CODE="EXPOSE" NAME "; USE ARG" NAME RETURN CODE /* ROUTINE SURROUNDS VARIABLES WITH DOUBLE QUOTES */ ::ROUTINE QUOTE PARSE ARG VALUE RETURN '"'||VALUE||'"' Running the above program yields the following output: VCARD30::The VCARD30 class: INIT CLASS, self~attr=[ATTR] [ADR::The ADR class]: INIT CLASS, top: self~attr=[ATTR] [ADR::The ADR class]: INIT CLASS, bottom: self~attr=[an Array] VCARD30::The VCARD30 class: INIT CLASS, self~attr=[ATTR] -------------------------------------------------- Defined methods for instances of [The ADR class]: [INIT] ------- Because of this it is not possible to take advantage of the inheritance behaviour and make it easy to complete the creation of classes at runtime using class constructors. Giving dozens of types in the vCalendar and vCard standards, implementing this at each subclass level means that a lot of hand-coding and/or copying must take place. This is not needed at the instance level, and as class objects are "normal objects" there should be no exception there. Conceptually, I would therefore think that this is a bug. But before filing a bug, I would like to learn whether this is a feature, and if so, what the reasoning would be. ---rony |