WHAT’S A TYPE?

From this point forward I’ll favor the term type over the term domain. So what is a type, exactly? In essence, it’s a named, finite set of values—all possible values of some specific kind: for example, all possible integers, or all possible character strings, or all possible supplier numbers, or all possible XML documents, or all possible relations with a certain heading (and so on). To elaborate briefly:

  • The types we’re interested in are always finite because we’re dealing with computers, which (as pointed out in connection with type RATIONAL earlier in the chapter) are finite by definition.

  • Note also that qualifier named: Types with different names are different types.

Moreover:

  • Every value is of some type—in fact, exactly one type, except possibly if type inheritance is supported, a concept that’s beyond the scope of this book. Note: Since no value is of more than one type, it follows that types are disjoint (nonoverlapping), by definition. However, perhaps I need to elaborate on this point briefly. As one reviewer of this chapter said, surely types WarmBloodedAnimal and FourLeggedAnimal overlap? Indeed they do; but what I’m saying is that if types overlap, then for a variety of reasons we’re getting into the realm of type inheritance—in fact, into the realm of what’s called multiple inheritance. Since those reasons, and indeed the whole topic of inheritance, are independent of the context we’re in, be it relational or something else, I’m not going to discuss them in this book.

  • Every variable, every attribute, every operator that returns a result, and every parameter of every operator is declared to be of some type.[25] And to say that, e.g., variable V is declared to be of type T means, precisely, that every value v that can legally be assigned to V is in turn of type T.

  • Every expression denotes some value and is therefore of some type: namely, the type of the value in question, which is to say the type of the value returned by the outermost operator in the expression (where by “outermost” I mean the operator that’s executed last). For example, the type of the expression

         ( a / b ) + ( x - y )

    is the declared type of the operator “+”, whatever that happens to be.

The fact that parameters in particular are declared to be of some type touches on an issue that I’ve mentioned but haven’t properly discussed as yet: namely, the fact that associated with every type there’s a set of operators for operating on values and variables of the type in question—where to say that operator Op is “associated with” type T means, precisely, that operator Op has a parameter of declared type T.[26] For example, integers have the usual arithmetic operators; dates and times have special calendar arithmetic operators; XML documents have what are called “XPath” and “XQuery” operators; relations have the operators of the relational algebra; and every type has the operators of assignment (“:=”) and equality comparison (“=”). Thus, any system that provides proper type support—and “proper type support” here certainly includes allowing users to define their own types—must provide a way for users to define their own operators, too, because types without operators are useless. Note: User defined operators can be defined in association with system defined types as well as user defined ones (or a mixture, of course), as you would surely expect.

Observe now that, by definition, values and variables of a given type can be operated upon only by means of the operators associated with that type. For example, in the case of the system defined type INTEGER:

  • The system provides an assignment operator “:=” for assigning integer values to integer variables.

  • It also provides a format for writing integer literals. (However, it doesn’t provide any selector operators more general than simple literals, nor does it provide any THE_ operators, because—as should be obvious if you think about it—such operators aren’t needed for a system defined type like INTEGER.)

  • It also provides comparison operators “=”, “≠”, “<”, and so on, for comparing integer values.

  • It also provides arithmetic operators “+”, “*”, and so on, for performing arithmetic on integer values.

  • It does not provide string operators “||” (concatenate), SUBSTR (substring), and so on, for performing string operations on integer values; in other words, string operations on integer values aren’t supported.

By contrast, in the case of the user defined type SNO (still assuming it is user defined), we would certainly define the necessary selector and THE_ operators, and we would also define assignment (“:=”) and comparison operators (“=”, “≠”, possibly “<”, and so on). However, we probably wouldn’t define operators “+”, “*”, and so on, which would mean that arithmetic on supplier numbers wouldn’t be supported (what could it possibly mean to add or multiply two supplier numbers?).

From everything I’ve said so far, then, it should be clear that defining a new type involves at least all of the following:

  1. Defining a name for the type (obviously enough).

  2. Defining the values that make up that type. I’ll discuss this aspect in detail in Chapter 8.

  3. Defining the hidden physical representation for values of that type. As noted earlier, this is an implementation issue, not a model issue, and I won’t discuss it further in this book.

  4. Defining a selector operator for selecting, or specifying, values of that type.

  5. Defining the operators—including in particular assignment (“:=”), equality comparison (“=”), and THE_ operators—that apply to values and variables of that type (see below).

  6. For those operators that return a result, defining the type of that result (again, see below).

Observe that points 4, 5, and 6 taken together imply that the system knows precisely which expressions are legal, and for those expressions that are legal it knows the type of the result as well.

By way of example, suppose we have a user defined type POINT, representing geometric points in two-dimensional space. Here then is the Tutorial D definition—I could have used SQL, but operator definitions in SQL involve a number of details that I don’t want to get into here—for an operator called REFLECT which, given a point P with cartesian coordinates (x,y), returns the “reflected” or “inverse” point with cartesian coordinates (-x,-y):

  1. OPERATOR REFLECT ( P POINT ) RETURNS POINT ;
  2.    RETURN POINT ( - THE_X ( P ) , - THE_Y ( P ) ) ;
  3. END OPERATOR ;

Explanation:

  • Line 1 shows that the operator is called REFLECT; takes a single parameter P, of type POINT; and returns a result also of type POINT (so the declared type of the operator is POINT).

  • Line 2 is the operator implementation code. It consists of a single RETURN statement. The value to be returned is a point, and it’s obtained by invoking the POINT selector; that invocation has two arguments, corresponding to the X and Y coordinates of the point to be returned. Each of those arguments is defined by means of a THE_ operator invocation; those invocations yield the X and Y coordinates of the point argument corresponding to parameter P, and negating those coordinates leads us to the desired result.[27]

  • Line 3 marks the end of the definition.

Now, the discussions in this section so far have been framed in terms of user defined types, for the most part. But similar considerations apply to system defined types also, except that in this case the various definitions are furnished by the system instead of by some user. For example, if INTEGER is a system defined type, then it’s the system that defines the name, defines legal integer values, defines the hidden representation, and—as we’ve already seen—defines a corresponding literal format, defines the corresponding operators “:=”, “=”, “+”, and so on (though users can define additional operators as well, of course).

There’s one last point I want to make. I’ve mentioned selector operators several times; what I haven’t said, however (at least not explicitly), is that selectors—more precisely, selector invocations—are really just a generalization of the more familiar concept of a literal.[28] What I mean by this remark is that all literals are selector invocations, but not all selector invocations are literals (in fact, a selector invocation is a literal if and only if its arguments are themselves all specified as literals in turn). For example, POINT(X,Y) and POINT(1.0,2.5) are both invocations of the POINT selector, but only the second is a POINT literal. It follows that every type has (must have) an associated format for writing literals. And for completeness I should add that every value of every type must be denotable by means of some literal.



[25] Throughout this book I treat declared and defined as synonymous.

[26] The logical difference between type and representation is important here. To spell the matter out, the operators associated with type T are the operators associated with type Tnot the operators associated with the representation of type T. For example, just because the representation for type SNO happens to be CHAR (say), it doesn’t follow that we can concatenate two supplier numbers; we can do that only if concatenation is an operator that’s defined for type SNO. (In fact I did mention exactly this example in passing in the section EQUALITY COMPARISONS, as you might recall.)

[27] This paragraph touches on another important logical difference, incidentally: namely, that between arguments and parameters (see Exercise 2.5 at the end of the chapter). Note too that the POINT selector, unlike the SNO and PNO selectors discussed earlier, takes two arguments (because points are represented by pairs of values, not just by a single value).

[28] The concept might be familiar, but it seems to be quite difficult to find a good definition for it in the literature! See Exercise 2.2.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.36.72