    """Abstract supertype of objects that contain other values,
       called *elements*, where it is possible to efficiently
       determine if a given value is an element. A `Category`
       may not be finite, and its elements may not even be
       countable. Thus, unlike [[streams|Iterable]], the
       elements of a generic `Category` are not iterable.

       `Category` models a mathematical set, but is distinct
       from the [[Set]] collection type which represents finite
       sets.

       The `in` operator may be used to determine if a value
       belongs to a `Category`:

           if (69 in 0..100) { ... }
           assert (key->item in { for (n in 0..100) n.string->n**2 });

       An object may be a `Category` of two different disjoint
       element types. For example, [[String]] is a `Category`
       of its `Character`s and of its substrings.

           if ("hello" in "hello world") { ... }
           assert ('.' in string);

       Every meaningful `Category` is formed from elements with
       some equivalence relation. Ordinarily, that equivalence
       relation is [[value equality|Object.equals]]. Thus,
       ordinarily, `x==y` implies that `x in cat == y in cat`.
       But this contract is not required since it is possible to
       form a meaningful `Category` using a different
       equivalence relation. For example, an `IdentitySet` is a
       meaningful `Category`, where the equivalence relation is
       [[identity equality|Identifiable]].

       Since [[Null]] is not considered to have any meaningful
       equivalence relation, a `Category` may not contain the
       [[null value|null]].

       Note that even though `Category<Element>` is declared
       contravariant in its [[element type|Element]], most types
       that inherit `Category` are covariant in their element
       type, and therefore satisfy `Category<Object>`, resulting
       in some loss of typesafety. For such types, [[contains]]
       should return `false` for any value that is not an
       instance of the element type. For example, `String` is a
       `Category<Object>`, not a `Category<Character|String>`,
       and `x in string` evaluates to `false` for every `x` that
       is not a `String` or `Character`."""
    by ("Gavin")
    tagged("Collections")
    shared interface Category<in Element=Object>
            given Element satisfies Object {

        "Returns `true` if the given value belongs to this
         `Category`, that is, if it is an element of this
         `Category`, or `false` otherwise.

         For any instance `c` of `Category`, `c.contains(element)`
         may be written using the `in` operator:

             element in c

         For most `Category`s, the following relationship is
         satisfied by every pair of elements `x` and `y`:

         - if `x==y`, then `x in category == y in category`

         However, it is possible to form a useful `Category`
         consistent with some other equivalence relation, for
         example `===`. Therefore implementations of `contains()`
         which do not satisfy this relationship are tolerated."
        see (`function containsEvery`, `function containsAny`)
        shared formal Boolean contains(Element element);

        "Returns `true` if every one of the given values belongs
         to this `Category`, or `false` otherwise."
        see (`function contains`, `function containsAny`)
        shared default
        Boolean containsEvery({Element*} elements) {
            for (element in elements) {
                if (!contains(element)) {
                    return false;
                }
            }
            else {
                return true;
            }
        }

        "Returns `true` if any one of the given values belongs
         to this `Category`, or `false` otherwise."
        see (`function contains`, `function containsEvery`)
        shared default
        Boolean containsAny({Element*} elements) {
            for (element in elements) {
                if (contains(element)) {
                    return true;
                }
            }
            else {
                return false;
            }
        }

    }