## 5.2. Defining the Range of an Attribute

An attribute may be viewed as a function that assigns an attribute value to an entity. Like a mathematical function, an attribute has a *domain* and a *range*. The domain of an attribute is the entity type for which the attribute has been defined. Its range is a datatype such as *String* or *Integer*.

In a design model, we use platform-independent datatypes such as String, Integer, Decimal, Date, Boolean, Currency, etc, as shown in Figure 5-3, which have to be mapped to corresponding platform-specific datatypes later when the design model is converted into a platform-specific data model. For instance, the platform-independent datatype *Decimal* is normally mapped to `double`

in Java, to `number`

in JavaScript, to `REAL`

in SQLite, and to `DECIMAL`

or `FLOAT`

in MySQL.

Assigning a range to an attribute means defining a *range constraint*, which requires that an attribute must have a value from its range. For instance, when (for an entity type *Person*) the attribute *age* is defined with the range *Integer*, it must not have a value like "abc", which does not denote an integer. However, it may still have values like -13 or 321, which also do not make sense as the age of a person. In a similar way, when the range of the attribute *name* is defined as *String*, it may have the value "" (the empty string), which is a valid string that does, however, not make sense as a name.

This consideration shows that it is preferable to assign a specific datatype as the range of an attribute for specifying a more precise range constraint. For instance, a more specific range for the attribute *age* would be *NonNegativeInteger* instead of *Integer*, for an attribute like *seasonNumber* it would be *PositiveInteger* instead of *Integer*, and for attributes like *name* or *title* it would be *NonEmptyString* instead of *String*.

Notice that these more specific datatypes are neither predefined in SQL nor in common programming languages, so we have to implement them either in the form of user-defined types, as supported in SQL-99 data base management systems such as PostgreSQL, or by using additional constraints such as interval constraints or pattern constraints, which are discussed in Section 5.4.

In a UML class modeling tool, we can define specific datatypes as custom datatypes and then use them in class diagrams, as illustrated in Figure 5-4.

#### String Datatypes

The basic datatype *String* allows for the special value "" (the empty string) as well as many forms of blank space strings such as " " or " ". In many cases of string-valued attributes, neither the empty string nor any blank space string are admissible. These attributes should be defined with the more specific datatype *NonEmptyString* as their range.

There are also string-valued attributes, the values of which have to comply with a special format. The email, phone number or homepage URL of a person are examples of such special types of strings. In these cases, it is preferable to use specific datatypes such as `Email`

, * URL* or

*in an information design model for specifying a precise range constraint.*

`PhoneNumber`

#### Numeric Datatypes

Computational languages normally include support for the basic distinction between the mathematical number types *integers* and *decimals*. However, while numbers in mathematics can be arbitrarily large and small, when numbers are represented in a computational form (also called *machine numbers*), they are always in a bounded range with a lower and an upper bound. Also, while the results of computations with mathematical numbers are precise, the results of computations with machine numbers may be out of range or imprecise due to rounding.

However, in a design model, it is not important how numbers are implemented in a technology. Therefore, implementation-agnostic datatypes, like *Integer* and *Decimal*, are used.

There are also more specific numeric datatypes, which allow to specify more precise range constraints. For specifying precise integer range constraints, we can use the integer types *NegativeInteger*, *NonNegativeInteger*, and *PositiveInteger*. For specifying precise decimal range constraints, we can use the decimal types *NegativeDecimal*, *NonNegative*Decimal, and *PositiveDecimal.*