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
A
is a scalar type andA
is a subtype ofB
thenB
is 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
A
is a subtype ofB
andB
is a scalar type thenA
is a scalar type of a union type in which any variant is a subtype ofB
. -
Suppose that
A
andB
are scalar types.Then
A
is subtype ofB
if and only if the following conditions hold:-
A
andB
are the same type orA
is at.integer()
andB
is at.float()
; -
Type constraints defined on
B
are all defined onA
and satisfy:Type Type Constraint Condition t.integer()
,t.float()
min
A.min >= B.min
t.integer()
,t.float()
x_min
A.x_min >= B.x_min
t.integer()
,t.float()
max
A.max <= B.max
t.integer()
,t.float()
x_max
A.x_max <= B.x_max
t.integer()
,t.float()
multiple_of
A.multiple_of
is a multiple ofB.multiple_of
t.string()
min
A.min >= B.min
t.string()
max
A.max <= B.max
t.string()
pattern
A.pattern == B.pattern
1t.string()
format
A.format == B.format
t.file()
min
A.min >= B.min
t.file()
max
A.max <= B.max
t.file()
allow
A.allow
is a subset ofB.allow
Note that type constraints defined on
A
are not required to be defined onB
. -
If
B
is an enum, thenA
is an enum and all enumeration values defined forA
are defined forB
.
-
Optionals
-
A
is a subtype oft.optional(B)
if and only ifA
is subtype ofB
. -
t.optional(A)
is a subtype oft.optional(B)
if and only ifA
is a subtype ofB
. -
If
B
is not an optional type, thent.optional(A)
is not a subtype ofB
.
Lists
-
Suppose that
A
andB
are non-optional types andA
is a subtype ofB
. IfA
is a list thenB
is a list and vice-versa. -
Let
X
a list type whose item type isA
, andY
a list type whose item type isB
.X
is a subtype ofY
if and only ifA
is a subtype ofB
,- Type constraints defined on
X
are all defined onY
and satisfy:Type constraint Condition min
X.min >= Y.min
max
X.max <= Y.max
unique_items
X.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
A
andB
are non-optional types andA
is a subtype ofB
. IfA
is an object type thenB
is an object type, and vice-versa. -
If
A
andB
are object types, thenA
is a subtype ofB
if and only if- All field key defined in
A
is defined inB
, - For all field defined in
B
with key K, either the field is optional onB
orA
has a field with key K whose type is a subtype of the one inB
; - Type constraints defined on
B
are all defined onA
and satisfy:Type constraint Condition min
A.min >= B.min
max
A.max <= B.max
- All field key defined in
Unions: t.union()
and t.either()
-
If
A
is a type andV
a list of types thenA
is a subtype oft.union(V)
if and only if there is a typeB
inV
such thatA
is a subtype ofB
. -
If
A
is a type andV
a list of types thenA
is a subtype oft.either(V)
if and only if there is a unique typeB
inV
such thatA
is a subtype ofB
. -
If
U
is a list of types andB
a type thent.union(U)
is a subtype ofB
if and only if each typeA
inU
is a subtype ofB
;t.either(U)
is a subtype ofB
if and only if each typeA
inU
is 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. ↩