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
-
If
Ais a scalar type andAis a subtype ofBthenBis a scalar type or a union type with at least one variant that is a supertype ofA.Note that this is stricter than it should be because we currently only check individually on each union variant.
-
If
Ais a subtype ofBandBis a scalar type thenAis a scalar type of a union type in which any variant is a subtype ofB. -
Suppose that
AandBare scalar types.Then
Ais subtype ofBif and only if the following conditions hold:-
AandBare the same type orAis at.integer()andBis at.float(); -
Type constraints defined on
Bare all defined onAand satisfy:Type Type Constraint Condition t.integer(),t.float()minA.min >= B.mint.integer(),t.float()x_minA.x_min >= B.x_mint.integer(),t.float()maxA.max <= B.maxt.integer(),t.float()x_maxA.x_max <= B.x_maxt.integer(),t.float()multiple_ofA.multiple_ofis a multiple ofB.multiple_oft.string()minA.min >= B.mint.string()maxA.max <= B.maxt.string()patternA.pattern == B.pattern1t.string()formatA.format == B.formatt.file()minA.min >= B.mint.file()maxA.max <= B.maxt.file()allowA.allowis a subset ofB.allowNote that type constraints defined on
Aare not required to be defined onB. -
If
Bis an enum, thenAis an enum and all enumeration values defined forAare defined forB.
-
Optionals
-
Ais a subtype oft.optional(B)if and only ifAis subtype ofB. -
t.optional(A)is a subtype oft.optional(B)if and only ifAis a subtype ofB. -
If
Bis not an optional type, thent.optional(A)is not a subtype ofB.
Lists
-
Suppose that
AandBare non-optional types andAis a subtype ofB. IfAis a list thenBis a list and vice-versa. -
Let
Xa list type whose item type isA, andYa list type whose item type isB.Xis a subtype ofYif and only ifAis a subtype ofB,- Type constraints defined on
Xare all defined onYand satisfy:Type constraint Condition minX.min >= Y.minmaxX.max <= Y.maxunique_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()
-
Suppose that
AandBare non-optional types andAis a subtype ofB. IfAis an object type thenBis an object type, and vice-versa. -
If
AandBare object types, thenAis a subtype ofBif and only if- All field key defined in
Ais defined inB, - For all field defined in
Bwith key K, either the field is optional onBorAhas a field with key K whose type is a subtype of the one inB; - Type constraints defined on
Bare all defined onAand satisfy:Type constraint Condition minA.min >= B.minmaxA.max <= B.max
- All field key defined in
Unions: t.union() and t.either()
-
If
Ais a type andVa list of types thenAis a subtype oft.union(V)if and only if there is a typeBinVsuch thatAis a subtype ofB. -
If
Ais a type andVa list of types thenAis a subtype oft.either(V)if and only if there is a unique typeBinVsuch thatAis a subtype ofB. -
If
Uis a list of types andBa type thent.union(U)is a subtype ofBif and only if each typeAinUis a subtype ofB;t.either(U)is a subtype ofBif and only if each typeAinUis a subtype ofB.
Examples
You can find examples of type comparison in the type comparison test suite.
Footnotes
-
The patterns are required to be exactly the same because we currently do not have any other comparison semantic for regular expressions. ↩