3 Cardinality Constraints and 1NF

In conventional languages (SQL, OO, functional languages, JSON, UML), type and cardinality are tightly linked. If something may occur zero times, one time, or many times, the type must change: T, Optional<T>, List<T>, Set<T>, typed tuples, arrays, and so on.

Predica separates these two concepts entirely. For a given attribute the type describes what kind of value may occur in its extension and the cardinality constraint describes how many values may occur in its extension. This follows naturally from interpreting attributes as unary predicates.

For this reason the cardinality constraint is written on the attribute, not inside its type:


Email email*;

The attribute email is singular, and its declared type Email is singular too. Even so, the * cardinality constraint allows the email predicate to hold for zero or more email address values.

Attaching cardinality to attributes rather than to types looks unconventional, yet it cleanly separates “what” from “how many”, enabling flexible modelling without proliferating container types.

The natural-language predicate is likewise phrased in the singular:

    email(E) ⇔ The person has an email address E

In the formula email(E), the parameter E ranges over individual values of type Email. The extension of the email predicate may contain many such values, but each value is still a single Email value.

The 1NF distinction in Predica

In this specification the following definition of 1NF is used:

This has nothing to do with whether attribute types are simple, and it has nothing to do with the declared cardinality constraints.

Under this definition this satisfies 1NF:


entity Person
{
    String name;
    Email email*;
    key {name};
}

whereas this is a violation of 1NF:


entity Person
{
    String name;
    Set<Email> emails;
    key {name};
}

Ironically, cardinality constraints that allow multiplicity might appear to violate 1NF and they indeed allow for multiple values in attribute extensions, yet the whole point is to preserve 1NF. They allow a predicate to hold for zero, one, or many values while keeping each value singular.