Skip to main content

Type comparison

A type A is called a subtype of a type B if any valid value for A is a valid value for B. This means that B has a broader range of values.

The "is subtype of" relation between types is partial order relation equivalent to the "is subset of" relation (set inclusion) if types were defined as a set of values. Note that the reflexivity of partial orders translates to "for all type A, A is a subtype of A".

This type comparison is required for the validation of from parent injections.

Semantics

In this section A and B denote types, U and V denote lists of types.

If A is a subtype of B, then A and B are either both scalar types or both non-scalar types.

Scalar types

  1. If A is a scalar type and A is a subtype of B then B is a scalar type or a union type with at least one variant that is a supertype of A.

    Note that this is stricter than it should be because we currently only check individually on each union variant.

  2. If A is a subtype of B and B is a scalar type then A is a scalar type of a union type in which any variant is a subtype of B.

  3. Suppose that A and B are scalar types.

    Then A is subtype of B if and only if the following conditions hold:

    • A and B are the same type or A is a t.integer() and B is a t.float();

    • Type constraints defined on B are all defined on A and satisfy:

      TypeType ConstraintCondition
      t.integer(), t.float()minA.min >= B.min
      t.integer(), t.float()x_minA.x_min >= B.x_min
      t.integer(), t.float()maxA.max <= B.max
      t.integer(), t.float()x_maxA.x_max <= B.x_max
      t.integer(), t.float()multiple_ofA.multiple_of is a multiple of B.multiple_of
      t.string()minA.min >= B.min
      t.string()maxA.max <= B.max
      t.string()patternA.pattern == B.pattern1
      t.string()formatA.format == B.format
      t.file()minA.min >= B.min
      t.file()maxA.max <= B.max
      t.file()allowA.allow is a subset of B.allow

      Note that type constraints defined on A are not required to be defined on B.

    • If B is an enum, then A is an enum and all enumeration values defined for A are defined for B.

Optionals

  1. A is a subtype of t.optional(B) if and only if A is subtype of B.

  2. t.optional(A) is a subtype of t.optional(B) if and only if A is a subtype of B.

  3. If B is not an optional type, then t.optional(A) is not a subtype of B.

Lists

  1. Suppose that A and B are non-optional types and A is a subtype of B. If A is a list then B is a list and vice-versa.

  2. Let X a list type whose item type is A, and Y a list type whose item type is B. X is a subtype of Y if and only if

    • A is a subtype of B,
    • Type constraints defined on X are all defined on Y and satisfy:
      Type constraintCondition
      minX.min >= Y.min
      maxX.max <= Y.max
      unique_itemsX.unique_items == Y.unique_items

Note that the type constraints defined on X are not required to be defined on Y.

Objects: t.struct()

  1. Suppose that A and B are non-optional types and A is a subtype of B. If A is an object type then B is an object type, and vice-versa.

  2. If A and B are object types, then A is a subtype of B if and only if

    • All field key defined in A is defined in B,
    • For all field defined in B with key K, either the field is optional on B or A has a field with key K whose type is a subtype of the one in B;
    • Type constraints defined on B are all defined on A and satisfy:
      Type constraintCondition
      minA.min >= B.min
      maxA.max <= B.max

Unions: t.union() and t.either()

  1. If A is a type and V a list of types then A is a subtype of t.union(V) if and only if there is a type B in V such that A is a subtype of B.

  2. If A is a type and V a list of types then A is a subtype of t.either(V) if and only if there is a unique type B in V such that A is a subtype of B.

  3. If U is a list of types and B a type then

    • t.union(U) is a subtype of B if and only if each type A in U is a subtype of B;
    • t.either(U) is a subtype of B if and only if each type A in U is a subtype of B.

Examples

You can find examples of type comparison in the type comparison test suite.

Footnotes

  1. The patterns are required to be exactly the same because we currently do not have any other comparison semantic for regular expressions.