Identity and Equality

William Kent and Amelia Carlson
Hewlett-Packard
kent@hpl.hp.com

1993

SQL3 Change Proposal
ISO Number: WG3 DBL MUN-62
ANSI Number: X3H2-93-109R2
1993
Title: Identity and Equality
Author: William Kent and Amelia Carlson

References:

1 Melton, Jim (ed.), "(ISO/ANSI Working Draft) Database Language SQL3", X3H2-93-359R, ISO WG3 DBL MUN-003.

2 Melton, Jim (ed.), "(ISO/ANSI Working Draft) Database Language SQL3", X3H2-93-091, ISO WG3 DBL YOK-003.

3 Kent, William, "SQL3 OO Underlying Assumptions", X3H2-93-076, ISO WG3 DBL YOK-38. [html] [postscript]

4 Carlson, Amelia, "Discussion of SQL3 OO Underlying Assumptions", X3H2-93-095, ISO WG3 DBL YOK-38 attachment.

5 Carlson, Amelia and William Kent, "Subtyping and Casting", X3H2-93-110, ISO WG3 DBL YOK-75.


CONTENTS:
> 1 RATIONALE . . . 2
>> 1.1 Uniquely determining an object . . . 3
>> 1.2 Equality of ADT instances (default semantics) . . . 4
>> 1.3 Notes for user-defined equality . . . 5
>> 1.4 NEW and DESTROY on value ADTs . . . 6
>> 1.5 Value ADTs and CONSTRUCTOR functions . . . 7
>> 1.6 Examining DESIGNATORS further . . . 7
> 2 PROPOSED CHANGES . . . 8
>> 2.1 Clarify object ADT identity . . . 8
>>> 2.1.1 Fold REFness into object ADTs . . . 8
>>> 2.1.2 Add ATTRIBUTES function in place of REF/DEREF . . . 11
>> 2.2 Default equality for ADTs . . . 13
>> 2.3 Notes for user-defined equality . . . 14
>> 2.4 Remove NEW and DESTROY for value ADTs . . . 14
>> 2.5 DESIGNATOR instead of CONSTRUCTOR for value ADTs . . . 16


1 RATIONALE

Identity versus Equality was one of the areas receiving much discussion when paper X3H2-93-076 was discussed at the X3H2 meeting in January 1993. As such, this paper proposes some clarifications in this area as well as some changes that simplify the model and increase its usability.

We begin with some definitions to aid the discussion.

It is today the case that a distinct new object is created with each execution of a NEW statement on an object ADT, which assigns the new object a distinct new object identifier (oid).

We will use the following example type hierarchy in explaining the ideas:

CREATE TYPE Person WITH OID (Name CHAR(40));
CREATE TYPE Teacher WITH OID UNDER Person (Salary DECIMAL(10,2));
CREATE TYPE Student WITH OID UNDER Person (GPA DECIMAL(7,5));
CREATE TYPE Intern WITH OID UNDER Teacher, Student (Supervisor Teacher);

We will refer to a `column' in an ADT as an attribute in an ADT, to differentiate it from the notion of table columns. The SQL3 document makes this differentiation to some extent in use of ADTs, but the definition of an attribute uses <column definition>.

There are four possible tuples that might conceptually be associated with an instance of a given ADT.

Local object tuple (LOT): OID + attributes defined on the ADT.
Local attribute tuple (LAT): attributes defined on the ADT.
Cumulative object tuple (COT): LOT + inherited attributes.
Cumulative attribute tuple (CAT): LAT + inherited attributes.

In the specifications today, the COT is what is available for an object ADT and the CAT is available for a value ADT (since it has no OID). We do not imply that OID (or, for that matter, PRIVATE or PROTECTED attributes) are accessible elements of an object tuple.

For a maximal type, the local and cumulative tuples are the same.

For the purpose of this paper, object ADTs are the main point of interest. However, we will (as we have just done) show how value ADTs fit into the concepts.

1.1 Uniquely determining an object

The contents of an object tuple are uniquely determined by an oid and an ADT. The semantics are as though there was only one copy of such a tuple, even if implementations choose to maintain replicas. As we will show later, there appears to be no cases where instance of ADT behaves differently from REF(instance of ADT). [Except, perhaps, that a few rules for dealing with REF in place of ADT appear to be missing; the follow-on proposals to add REF have not yet been written.] In fact, there is a clear one-to-one correspondence between an oid and the tuple of an object. Because of this, if we define the object ADT instances appropriately, as the oid and not the associated state, we do not lose information. All associated attributes of an object are accessible from the OID (this is, in fact, true in SQL3 today).

Thus, for object ADTs, there seems to be no need to maintain a REF type or the REF and DEREF functions. The ADT instance contains the oid information, and assigning values to object ADT columns appears to be handled for both REF(ADT) and ADT types synonymously for object ADTs. (For value ADTs, REF is not valid, since there is no OID for the REF to return.)

There are three places to use an object ADT to make ADT instances persistent:

What's the difference in the two columns? Well, the FirstCousin column holds an ADT instance, and the SecondCousin column holds an oid of an ADT instance. Does that turn out to be relevant? If I pass either column to a routine, I either have to REF the first (to match a REF(Person) parameter type) or DEREF the second (to match a Person parameter type); but regardless, I can refer to attributes the same way. Thus, both code segments below are valid:

DECLARE LocalCousin Person;
BEGIN
SET :LocalCousin.Name = `Mary Jones';
END;

DECLARE DistantCousin REF(Person);
BEGIN
SET :DistantCousin.Name = `Mary Jones';
END;

The rules in <attribute reference> make both of these valid, with an implicit DEREF occurring in the second case. Similarly, the rules for <new statement> in the ISO document require a REF variable (the ANSI document makes no type requirement (see 14.8 <new statement>, SR 2)), which appears to be an omission); this ensures an object ADT is used, but instead we could have an implicit REF of an ADT variable.

If I want to insert to either column I have to assign an ADT instance (or REF of one) to it (this can be done in today's SQL3 either by invoking a CONSTRUCTOR function or by assigning it an existing ADT value from a row of an ADT table, for instance). In either case, I have an ADT value, which consists of an oid and attribute values, associated with the column. The only questions arise when I attempt to pass it to functions, whether I have to REF or DEREF it due to the way the ADT definer defined the type as compared to the way I defined my column (or local variable). Since a REF type instance contains only an OID and knowledge that it is for a certain ADT, and the REF function can get to the ADT instance with that information, it seems redundant to have REF for this use.

We have seen it suggested in other papers that REF makes clear the meaning of comparisons of object instances. But the whole idea behind having object instances is that they have object identity, independent of their state. This is one of the key object-oriented paradigms. If object identity is not to be an issue, then a value ADT would have been a more appropriate choice.

However, we do not override the possibility of user-defined equality; thus, users are still able to override identity comparison if they want to use object ADTs as if they were value ADTs (since SQL3 also has value ADTs, it is not clear what this functionality provides, but it seems like a possible compromise).

Further, if the ADT designer decides on object identity being important in the object ADT, a function to get at the state of the ADT, its attribute values, can be included. This function is similar to DEREF but different in one important way; it returns a <row value expression>, not an ADT instance. The tuple that describes the ADT's state is not the ADT's type. This function will be discussed further below; the proposed name is ATTRIBUTES (since it returns the attributes of an ADT instance).

1.2 Equality of ADT instances (default semantics)

Let us take another look at this. Two of the four kinds of tuples (LOT, LAT, COT, and CAT) are associated with the instances of a given object ADT, namely LOT and COT. For an object which is an instance of n object ADT's (due to a type hierarchy), there are 2n such associated tuples (2n-1 distinct tuples, due to the fact that the maximal supertype has LOT=COT).

The corresponding tuples for our example (which uses an object ADT) are:

Person: LOT:<oid, Name> COT:<oid, Name>
Teacher: LOT:<oid, Salary> COT:<oid, Name, Salary>
Student: LOT:<oid, GPA> COT:<oid, Name, GPA>
Intern: LOT:<oid, Supervisor> COT:<oid, Name, Salary, GPA, Supervisor>

The idea of having an instance of an object ADT should refer to the oid, and not to any of the associated tuples. Note that an instance of a subtype is an instance of all of its supertypes (4.9.2, "Subtypes and supertypes", states: ``Any instance of a subtype is an instance of all of its supertypes. ... If T_a is a subtype of T_b, then an instance of T_a can be used wherever an instance of T_b is expected."). This is only true for the oid, because as an instance has its type altered (via assignment or routine invocation), the associated tuple changes (not only will the attributes involved change, but their names may also change if they were renamed in the subtype).

So, if an object ADT refers to the tuple associated with its most specific type, then if that instance is assigned to a supertype, it is not the case that that tuple is an instance of the supertype's associated tuple. See this example:

-- assume this is in a function that is an OPERATOR of both Person and Intern

DECLARE :P Person;
DECLARE :I Intern;
BEGIN
SET :I = Intern(`Mary', 7.50, 3.5, NULL);
SET :P = :I;
SET :P.GPA = 3.7; /* illegal, since GPA not in Person */
SET :I.GPA = 3.7; /* legal, since GPA is in Intern */
SET :I = :P; /* illegal, since Person not a subtype of Intern */
END;

Clearly, the attributes associated with Person are different from those associated with Intern. It is only the oid of an instance, such as the one we created above, that will remain invariant as the type of the instance is altered due to variable assignment or function invocation.

Because this is the case, and also because it is object identity that defines an instance of an object, we will further propose that the default EQUALS for an object ADT be OID (renamed from the existing REF keyword, since we remove that concept). For a value ADT, it remains DEFAULT, that is, attribute comparison (this is still an identity comparison, since the attributes of a value ADT define its identity). For clarity, DEFAULT is replaced by STATE since the default for object ADT is OID and for value ADT is STATE.

1.3 Notes for user-defined equality

We do not remove the ability to override this default equality, but do point out that several problems can arise from it; these are problems that the users of SQL must address if they choose to use these features. We do propose that a simple note be added to the rules for EQUALS which states:

Note: In order to provide behavior equivalent to the default semantics for equality, the function named in the EQUALS clause should define a predicate which is reflexive (:x=:x), symmetric (:x=:y if and only if :y=:x), and transitive (if :x=:y and :y=:z, then :x=:z).

Further, it should be recognized that if :x=:y in one type, and :x and :y are cast to another type to become :x' and :y', :x'=:y' may not hold if at least one of the types has overridden the default equality, or only one of the types is an object ADT with default equality.

Assignment and equality should work in tandem. Except where behavior such as truncation is exhibited, SET :x = :y should operate such that :x = :y evaluates to true (or unknown). This feature of the equality function may interact with any cast functions specified on the ADT.

In summary, let us restate our definitions. An object may be thought of as having an associated tuple containing its oid and all of the attributes of all of the ADT's of which the object is an instance (recall from 4.9.2 that an instance of a subtype is also an instance of all of its supertypes). When the object is playing the role of an instance of a particular ADT (through being in a variable, column or table of that type), the associated tuple appears to include only its oid and the attributes of that ADT.

SQL3 today requires that all rows in an ADT table have as their most specific type the type of the table; and the constructor is called directly for such rows. Thus, as a row of a table, an object only ever ``plays one role" -- that of its most specific type. However, the interaction of subtables and supertables again shows how a row ``shared" in the sub/supertable sense across tables changes roles with the various tables through which the row can be examined.

Thus, since an instance of an object ADT includes the oid and one cannot locally update the attributes of the ADT without affecting all other instances of the ADT with the same oid, then oid and ADT are all that is necessary and sufficient to access and use an object ADT instance (or simply, an object). Therefore, there is no difference whether your column is defined on ADT or on REF(ADT), since their behavior is identical.

The only difference appears to be one of physical implementation; ADT as a column type implies that the attributes of the ADT are stored directly in the column (and replica maintenance done), while REF(ADT) implies that the oid is stored and the attributes are accessible through that oid. However, since the behavior is the same, we should avoid specifying this physical behavior in the standard, and leave it to implementations to decide which method is preferable.

1.4 NEW and DESTROY on value ADTs

Returning to an earlier statement, we said:

It is today the case that a distinct new object is created with each execution of a NEW statement on an object ADT, which assigns the new object a distinct new object identifier (oid).

However, a NEW statement on a value ADT (an ADT defined WITHOUT OID) does not appear to do anything. The General Rules state:

1) A new ADT instance whose data type is the data type of the containing <abstract data type definition> or <table definition> is created and is assigned to the local variable LV identified by the <new object name>.

2) If LV has a column named OID, then assigned to it a unique object identifier value.

No new oid is created, since this is not an object ADT (GR 2). It is not clear what GR 1 does -- what does it mean to create a `new instance' of a value ADT? Clearly, if I have a value ADT Rational, with CONSTRUCTOR function

-- Rational is a value ADT with two attributes, NUM and DEN

CONSTRUCTOR FUNCTION CreateRational(:N INTEGER, :D INTEGER)
RETURNS Rational;
DECLARE :R Rational
BEGIN
NEW :R;
SET :R.NUM = :N;
SET :R.DEN = :D;
RETURN :R;
END;

I don't have to allocate space for the Rational, since the local variable should provide that. No other form of `creation' comes to mind either. It certainly shouldn't be forcing this instance to be distinct from all other instances. Thus, the NEW statement on value ADTs appears to be an empty operation. (In fact, if I define the CONSTRUCTOR function without the NEW statement, it functions just as well as it does with it.)

The question then becomes, why permit this operation on value ADTs? It only appears to confuse the issue of who has OIDs (object ADTs) and who does not (value ADTs). Perhaps it seems that it lets us define CONSTRUCTOR functions exactly the same way in both ADT cases. But we aren't, really, because the NEW statement behaves differently in either case, and for value ADTs it does nothing to assist `creation' of the value.

Thus, a restriction that NEW is only for object ADTs is defined in <abstract data type body> for the CONSTRUCTOR function and in <new statement>.

The DESTROY statement appears to suffer from the same problems except that it does not even explicitly state that the oid is no longer (and can never be) a valid oid in the database. It requests that the row be marked for deletion; but <delete statement: ...> already does this, so that is clearly redundant. It is also of note that <delete statement: searched> invokes the destructor function (not the default/special/implicit one named REMOVE_ADTN), and <delete statement: positioned> fails to invoke any destructor function. The is not a serious problem, just an oversight in the rules. However, this proposal will clarify those rules.

1.5 Value ADTs and CONSTRUCTOR functions

The instances of a value ADT always exist, whether or not they are currently persistent or used in a database, in the same sense that numbers exist. Thus a `constructor' function for a value ADT is a reference to an existing instance of the ADT, in the same sense that 1798541+89542 is a reference to an existing number (without regard to whether or not that number has ever been mentioned before). Such a `constructor' is better termed as a `designator', in the sense that it designates some existing thing rather than `creating' it. (This is the same sense in which NEW does not do any work for a value ADT.) The commonly used term `constructor' deserves avoidance, since it has the unintended connotation of creating something new.

This same argument is proposed for renaming the nonterminals such as <set value constructor> to be <set value designator>.

One or more designator functions can be defined for referring to the instances of a value ADT.

1.6 Examining DESIGNATORS further

One of the interesting concepts of ADTs that has not yet been examined is the separation of interface from implementation. The use of designators as a way of making value ADTs independent from their implementations leads to some interesting ideas.

Consider an example of a value ADT that is a geometric point in two-dimensional space. All such points exist, and they are immutable. They may be referenced (designated) by either rectangular or polar coordinates. Whether they are represented internally in one form or the other is a matter of implementation, not specified in the interface. (If specified, it should be considered an implementation hint.) What is required is some definition of when two designators are equal.

For example....

CREATE VALUE TYPE TwoDimensionalGeometricPoint P
ATTRIBUTES
Xcoord -> REAL,
Ycoord -> REAL,
Magnitude -> REAL,
Angle -> REAL
CONSTRAINTS
P.Magnitude = SQRT(P.Xcoord*P.Xcoord + P.Ycoord*P.Ycoord)
P.Ycoord = P.Xcoord * TAN(P.Angle);
DESIGNATORS
RectPoint(x REAL, y REAL): P.Xcoord=x, P.Ycoord=y;
PolarPoint(m REAL, a REAL): P.Magnitude=m; P.Angle=a;
EQUAL (RectPoint(x1,y1),RectPoint(x2,y2)): x1=x2, y1=y2;
EQUAL (PolarPoint(m1,a1),PolarPoint(m2,a2)): m1=m2, a1=a2;
EQUAL (RectPoint(x,y),PolarPoint(m,a)): m=SQRT(x*x+y*y), y=x*TAN(a);

This example is seen as a first look at some of the requirements we might place on the interface specifications. Attributes, constraints, designators, and equality comparisons all appear to be relevant interface information. Note that the attributes above are not defined to be stored, virtual, or otherwise; that is not relevant to the interface, only to the implementation.

2 PROPOSED CHANGES

As we discussed five different areas dealing with ADT instance identity and equality, we separate the proposal into the same five areas. The sixth discussion area was only food for thought at this point, and no proposal in this paper addresses it. These proposals can be considered independently, although they are meant to work together and interact cleanly.

2.1 Clarify object ADT identity

2.1.1 Fold REFness into object ADTs

Add the following definitions to 3.1.3 Definitions provided in this Standard, alphabetically into the existing list:

ee) object:] an instance of an object ADT; each instance is identified by a unique object identifier.

ff) object ADT:] an abstract data type defined WITH OID.

ww) value ADT:] an abstract data type defined WITHOUT OID.

Modify Subclause 4.2 Data types:

After the third paragraph ("SQL also supports the collection data types..."), add a new fourth paragraph which reads:

SQL further supports SQL object identifier data types associated with the OID attribute of each object ADT. These data types cannot be used except implicitly as specified in this American/International standard.

At the end of the paragraph "SQL defines distinct data types named by...", replace "INTERVAL, and REF" with "and INTERVAL" in the list of data types.

Modify Subclause 4.9 Object identifier type:

Change the contents of the type descriptor to contain:

--- an indication that this is an object identifier type; and

--- the name of the abstract data type within which the object identifier type is used.

Replace the paragraph that begins "Conceptually, every object has an OID,...", as value ADTs have no object identifier generated by the NEW statements (since they have no OID column), with:

The object identifier type is only used to define the OID pseudo column implicitly defined in object ADTs within an ADT definition.

Modify Subclause 4.11 Abstract data types:

Remove the last sentence ("A value of an abstract data type is comparable only to another....") of the first paragraph; this is handled more fully in 4.13 (see changes below).

Replace the descriptor items for the equals operation and less-than operation with (since all of the keywords except for NONE are replaced by implicit functions in the ADT definition, only NONE needs to be spelled out):

--- the name of the equals operation for the abstract data type;

--- the name of the less-than operation for the abstract data type, or NONE, as appropriate;

In Subclause 4.13 Type conversions and mixing of data types, replace (ISO) paragraphs seven through eleven (the paragraph starting "Values corresponding to abstract data types ..." through the paragraph starting "A value corresponding to an abstract data type REF(T1)...") with:

Values corresponding to abstract data types are mutually comparable if both are in the same subtype family. A value of an abstract data type ADTi is assignable to an item of abstract data type ADTj if ADTi is a subtype of ADTj.

A value corresponding to a value ADT is not comparable to a value corresponding to an object ADT. Note: Explicit CAST functions or attribute comparisons must be used to make both values of the same subtype family or to perform the comparisons on attributes of the ADTs. Note: "subtype" and "subtype family" are defined in Subclause 4.10, "Subtypes and supertypes".

In 6.1 <data type>:

In the production for <predefined type>, delete the following:

| <object identifier type>

Remove the production for <object identifier type>,

<object identifier type> ::=
REF [ <left paren> <abstract data type name> <right paren> ]

Remove Syntax Rule 35 ("If <data type> is an <object identifier type> containing...").

Modify Leveling Rule 2 (Full SQL) b) ("A <predefined type> shall not be an ..."), removing ", or <object identifier type>". (Put the "or" between the remaining two choices.)

In clause 6.4 <attribute reference>:

Change SR 1 ("The data type of <value specification> shall be...") by removing the text "or shall be an object identifier type that is qualified by an abstract data type name".

In Subclause 6.14 <cast specification>:

Remove the column and row named OID from the table in SR 4 ("If the <cast operand> is a <value expression> and neither TD nor..."), and the entry for OID from the key.

In Subclause 6.15 <value expression>:

In the production for <value expression>, delete the following:

| <object identifier value expression>

Delete the production for <object identifier value expression>:

<object identifier value expression> ::=
<value expression primary>

In SR 1 ("The data type and null class of a <value expression>..."), remove "or <object identifier value expression>", editorially inserting an "or" before the now-final item.

In Subclause 8.2 <comparison predicate>:

Modify Syntax Rule 4 ("If any pair of respective values has data type object identifier...") to read:

4) If any pair of respective values has a collection type, then <comp op> shall be either <equals operator> or <not equals operator>.

In Subclause 9.1 Retrieval assignment:

Remove GR 4("If V is not a null value...") subrule q) ("If the data type of T is object identifier, then the value of T is set to V").

In Subclause 9.2 Store assignment:

Remove GR 3 ("Otherwise, let V denote a non-null value...") subrule q) ("If the data type of T is object identifier, then the value of T is set to V").

In Subclause 9.3 Set operation result data types and nullabilities:

Remove SR 3 ("Case:") subrule j) ("If any data type in DTS is an object identifier type...").

In Subclause 11.6 <default clause>:

Remove Syntax Rule 3 ("Case:") subrule b) ("if the subject <data type> ... is the object identifier type...").

In Subclause 11.46 <abstract data type body>:

In SR 10 ("Let ADTN be the ..."), replace "that specifies "OID REF(ADTN) NOT NULL is implicit" with:

10) ... is implicitly specified that defines an attribute with <attribute name> OID, data type object identifier type with the associated abstract data type identified by ADTN, and the <column constraint definition> NOT NULL.

Modify SR 19 ("An <abstract data type definition> ADT is directly base on...") and 20 ("The actual base type...") to read:

19) An <abstract data type definition> ADT that defines an object ADT is directly based on its own object identifier type (which identifies ADT as the associated abstract data type). Otherwise, it is directly based on a data type DT if DT is the data type of an <attribute definition> of ADT. An <abstract data type definition> ADT is based on a data type DT if ADT is directly based on DT or if ADT is directly based on an abstract data type ADT2 that is based on DT.

20) The actual base type of a predefined type PDT is PDT. The actual base types of an abstract data type ADT are the predefined and object identifier types on which ADT is based, and, if they are derived from the components of ADT, the actual base types are in the order of the components of ADT.

2.1.2 Add ATTRIBUTES function in place of REF/DEREF

Make the following changes in 5.2 <token> and <separator>:

Remove the keywords REF and DEREF from the Format for <reserved word> (remove REF only if proposal 2.2 is accepted also).

Add the keyword ATTRIBUTES to the Format for <reserved word>.

Note to the editor: make the same changes in Annex E, in the list of new reserved words for SQL3.

Replace Subclause 6.11 <reference conversion function> with:

6.11 <attributes function>

Function

Specify a function to convert between an ADT instance and its value.

Format

<attributes function> ::=
ATTRIBUTES <left paren>
<abstract data type value expression> <right paren>

Syntax Rules

1) The data types of the column or columns of an <attributes function> are the data types of the stored components of the <abstract data type value expression>, excluding any component named OID.

2) The null class of an <attributes function> is the null class of the <abstract data type value expression> directly contained in <attributes function>.

Access Rules

None.

General Rules

1) The result of the <attributes function> is

Case:

a) If the <abstract data type value expression> is a null value, then that null value.

b) Otherwise, a row of columns whose i-th column has as its name the name of the i-th stored component in the ADT instance and as its value the value of the i-th stored component in the abstract data type instance that is the value of the <abstract data type value expression>, excluding any component named OID.

Leveling Rules

1) The following restrictions apply for Full SQL:

a) Conforming Full SQL language shall specify no <attributes function>.

2) The following restrictions apply for Intermediate SQL in addition to any Full SQL restrictions:

None.

3) The following restrictions apply for Entry SQL in addition to any Intermediate SQL restrictions:

None.

Modify 6.15 <value expression> as follows:

Replace <reference conversion function> in the Format for <value expression> with <attributes function>. In Syntax Rule 1 ("The data type and null class of a <value expression> are the data type and ..."), replace "<reference conversion function>" with "<attributes function>" (1 occurrence).

Replace Leveling Rule 1 (Full SQL) c) (for <reference conversion function>) with:

c) A <value expression> shall not specify an <attributes function>.

Index the new non-terminal <attributes function> and the keyword ATTRIBUTES, and de-index the removed non-terminals <reference conversion function>, <ref function>, and <deref function>, and keywords REF and DEREF.

2.2 Default equality for ADTs

Make the following changes in 5.2 <token> and <separator>:

Remove the keyword REF from the Format for <reserved word> (if proposal 2.1.2 is accepted also).

Add the keyword STATE to the Format for <reserved word>.

Make the following changes in 11.45 <abstract data type body>:

Alter the Format for <equals function specification> to be:

<equals function specification> ::=
<routine name>
| STATE
| OID

Replace Syntax Rule 23 ("If no <equals function specification> is present, then DEFAULT is implicit.") with:

Alter Syntax Rule 26) ("Case:") a) ("If <equals function specification> specifies DEFAULT, then:") to read:

Alter Syntax Rule 23) ("Case:") b) ("If <equals function specification> specifies REF, then:") to read:

"If <equals function specification> specifies OID, then:".

2.3 Notes for user-defined equality

Alter 11.46 <abstract data type body> as follows:

Add the following Note after SR 27 ("If a <routine name> is specified as an <equals function specification> ..."):

Note: In order to provide behavior retaining essential properties of equality, the <routine name> specified as an <equals function specification> should define a predicate which is reflexive (:x=:x), symmetric (:x=:y if and only if :y=:x), and transitive (if :x=:y and :y=:z, then :x=:z).

Further, it should be recognized that if :x=:y in one type, and :x and :y are cast to another type to become :x' and :y', :x'=:y' may not hold if at least one of the types has overridden the implicit <equals function specification>, or only one of the types is an object ADT with the <equals function specification> OID.

Assignment and equality should work in tandem. Except where behavior such as truncation is exhibited, "SET :x = :y" should operate such that "NOT :x IS DISTINCT FROM :y" evaluates to true. This feature of the equality function may interact with any cast functions specified on the ADT.

2.4 Remove NEW and DESTROY for value ADTs

This proposal restricts NEW and DESTROY to OID creation and deletion for object ADTs. It also cleans up the destructor invocation for delete statements.

In 11.46 <abstract data type body>:

Note: these changes are only needed if proposal 2.5 is not also accepted. Otherwise, that part will override the changes proposed here to 11.46.

Modify Syntax Rule 31 ("Case:") b) ("Otherwise, let ADTN be the..."; it is setting up the implicit constructor function) to read:

b) Otherwise, let ADTN be the <abstract data type name>; if ADTN is defined WITH OID, let NEW_STATEMENT be "NEW :TEMP;", otherwise let NEW_STATEMENT be nothing; the <abstract data type definition> contains an implicit <routine> ADTC:

CONSTRUCTOR FUNCTION ADTN (:C1 T1, ..., :Cn Tn )
RETURNS ADTN;
DECLARE :TEMP ADTN;
BEGIN
NEW_STATEMENT
SET :TEMP.C1 = :C1;
.
.
.
SET :TEMP.Cn = :Cn;
RETURN :TEMP;
END;

where, for each CONSTANT or UPDATABLE public attribute Ci of the ADT, there is a corresponding parameter Ci with the same name and the same data type.

Modify SR 32 ("Case:") subrule c ("Otherwise, let ADTN be the..."; it is setting up a default destructor function) to read:

b) Otherwise, let ADTN be the <abstract data type name>; if ADTN is defined WITH OID, let DESTROY_STATEMENT be "DESTROY :TEMP;", otherwise let DESTROY_STATEMENT be nothing; the <abstract data type definition> contains an implicit <routine> ADTD:

DESTRUCTOR FUNCTION REMOVE_ADTN (:TEMP ADTN)
RETURNS ADTN;
BEGIN
DESTROY_STATEMENT
RETURN NULL;
END;

In Clause 13.3 <routine>:

Note: if the proposal in part 2.5 is also accepted, the changes proposed to 13.2 in this part of the paper will no longer be necessary.

In SR 6 ("If the <routine header> of a <routine>...", subrule d ("If the <function type> is CONSTRUCTOR..."), subpart iv ("The <SQL routine body> shall contain exactly one <new statement>..."), reword subpart iv to read:

iv) If DT is defined WITH OID, then the <SQL routine body> shall contain exactly one <new statement>, and the operand of that statement shall be a parameter whose data type is DT; otherwise, no <new statement> shall be specified in the <SQL routine body>.

In SR 5 ("If the <routine header> of a <routine>...", subrule e ("If the <function type> is DESTRUCTOR..."), subpart iii ("The <SQL routine body> shall contain exactly one <destroy statement>..."), reword subpart iii to read:

ii) If DT is defined WITH OID, then the <SQL routine body> shall contain exactly one <destroy statement>, and the operand of that statement shall be the parameter whose data type is DT; otherwise, no <destroy statement> shall be specified in the <SQL routine body>.

In Subclause 14.6 <delete statement: positioned>:

Change GR 10 ("The row from which the current row...") to read:

10) If T contains a default destructor function, then that function is invoked with its <operand> being the object from which the current row of CR is derived. The row from which the current row of CR is derived is marked for deletion.

In Subclause 14.7 <delete statement: searched>:

Change GR 6 ("Case:") a ("If <search condition> is not specified,...") to read:

a) If <search condition> is not specified, then all rows of T are marked for deletion. For every row marked for deletion, if T is associated with an abstract data type ADT with a default destructor function, then the default destructor function for ADT is invoked with its <argument> being that row.

Change the first paragraph of GR 6) b) ("If <search condition> is specified...marked for deletion."), adding at the end of that paragraph:

b) ... For every row marked for deletion, if T is associated with an abstract data type ADT with a default destructor function, then the default destructor function for ADT is invoked with its <argument> being that row.

2.5 DESIGNATOR instead of CONSTRUCTOR for value ADTs

In 4.11 Abstract data type:

Add to the list of items in an ADT descriptor before the box [To Be Supplied]:

--- the routine name of the default constructor function;

--- if the abstract data type has a default destructor function, then the routine name of that default destructor function;

In 5.2 <token> and <separator>:

Add the new <reserved name> DESIGNATOR. (Also add it to Annex E and the index.)

In Subclause 11.46 <abstract data type body>:

Modify SR 31 (a case for the default constructor function) to read:

Modify SR 32 (a case for the default destructor function) by adding a new subrule a) that reads:

In Subclause 13.3 <routine>:

Modify the production for <function type> to read:

<function type> ::=
CONSTRUCTOR
| DESTRUCTOR
| DESIGNATOR
| ACTOR

Modify Syntax Rule 6 ("If the <routine header> of a <routine>...") subrule d ("If the <function type> is CONSTRUCTOR..."), adding a new subpart before subpart i that reads:

i) DT shall be an abstract data type that specifies WITH OID.

Modify Syntax Rule 6 ("If the <routine header> of a <routine>...") subrule e ("If the <function type> is DESTRUCTOR..."), adding a new subpart before subpart i that reads:

i) DT shall be an abstract data type that specifies WITH OID.

Modify Syntax Rule 6 ("If the <routine header> of a <routine>...") by adding a new subrule f that reads: