vec_ptype2() finds the common type for a pair of vectors, or dies trying. It forms the foundation of the vctrs type system, along with vec_cast(). This powers type coercion but should not usually be called directly; instead call vec_ptype_common().

# S3 method for logical
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

# S3 method for integer
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

# S3 method for double
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

# S3 method for complex
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

# S3 method for character
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

# S3 method for raw
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

# S3 method for list
vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

vec_ptype2(x, y, ..., x_arg = "", y_arg = "")

vec_default_ptype2(x, y, ..., x_arg = "", y_arg = "")


x, y

Vector types.


These dots are for future extensions and must be empty.

x_arg, y_arg

Argument names for x and y. These are used in error messages to inform the user about the locations of incompatible types (see stop_incompatible_type()).

Coercion rules

vctrs thinks of the vector types as forming a partially ordered set, or poset. Then finding the common type from a set of types is a matter of finding the least-upper-bound; if the least-upper-bound does not exist, there is no common type. This is the case for many pairs of 1d vectors.

The poset of the most important base vectors is shown below: (where datetime stands for POSIXt, and date for Date)

S3 dispatch

vec_ptype2() dispatches on both arguments. This is implemented by having methods of vec_ptype2(), e.g. vec_ptype2.integer() also be S3 generics, which call e.g. vec_ptype2.integer.double(). vec_ptype2.x.y() must return the same value as vec_ptype2.y.x(); this is not enforced for reasons of efficiency, but should be tested.

vec_ptype2() are not inherited, classes must explicitly implement the methods. There are two reasons for this:

  • The coercion hierarchy is often different from a class hierarchy. For instance the richer type between a tibble and a data frame is a tibble. Grouped data frames inherit from tibble, and so would by default inherit from tibble's vec_ptype2() method if inheritance was allowed. The method would then indicate that the richer type between a grouped data frame and a data frame is a tibble, which is wrong.

  • vec_ptype2() should be symmetric, i.e. it should return the same type no matter the order of the inputs. With inheritance, this isn't the case when two classes have a common parent class. For instance the richer type between a tsibble and a tibble is tsibble. Similarly, grouped data frames are a richer type than tibble. Both of these classess have tibble as common parent class. With inheritance, vec_ptype2(tsibble, gdf) would return a tsibble via the tsibble-tibble method. vec_ptype2(gdf, tsibble) would return a grouped data frame via the gdf-tibble method.

Because of the way double dispatch is implemented, NextMethod() does not work inside vec_ptype2() methods.

See vignette("s3-vector") for full details.