% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/faq-developer.R
\name{howto-faq-fix-scalar-type-error}
\alias{howto-faq-fix-scalar-type-error}
\alias{howto_faq_fix_scalar_type_error}
\title{FAQ - Why isn't my class treated as a vector?}
\description{
The tidyverse is a bit stricter than base R regarding what kind of
objects are considered as vectors (see the \link[=faq-error-scalar-type]{user FAQ} about this topic). Sometimes vctrs won’t
treat your class as a vector when it should.
\subsection{Why isn’t my list class considered a vector?}{

By default, S3 lists are not considered to be vectors by vctrs:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_list <- structure(list(), class = "my_class")

vctrs::vec_is(my_list)
#> [1] FALSE
}\if{html}{\out{</div>}}

To be treated as a vector, the class must either inherit from \code{"list"}
explicitly:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_explicit_list <- structure(list(), class = c("my_class", "list"))
vctrs::vec_is(my_explicit_list)
#> [1] TRUE
}\if{html}{\out{</div>}}

Or it should implement a \code{vec_proxy()} method that returns its input if
explicit inheritance is not possible or troublesome:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{#' @export
vec_proxy.my_class <- function(x, ...) x

vctrs::vec_is(my_list)
#> [1] FALSE
}\if{html}{\out{</div>}}

Note that explicit inheritance is the preferred way because this makes
it possible for your class to dispatch on \code{list} methods of S3 generics:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_generic <- function(x) UseMethod("my_generic")
my_generic.list <- function(x) "dispatched!"

my_generic(my_list)
#> Error in `UseMethod()`:
#> ! no applicable method for 'my_generic' applied to an object of class "my_class"

my_generic(my_explicit_list)
#> [1] "dispatched!"
}\if{html}{\out{</div>}}
}

\subsection{Why isn’t my data frame class considered a vector?}{

The most likely explanation is that the data frame has not been properly
constructed.

However, if you get an “Input must be a vector” error with a data frame
subclass, it probably means that the data frame has not been properly
constructed. The main cause of these errors are data frames whose \emph{base
class} is not \code{"data.frame"}:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{my_df <- data.frame(x = 1)
class(my_df) <- c("data.frame", "my_class")

vctrs::obj_check_vector(my_df)
#> Error:
#> ! `my_df` must be a vector, not a <data.frame> object.
#> x Detected incompatible data frame structure. A data frame is normally treated as a vector, but an incompatible class ordering was detected. To be compatible, the subclass <my_class> must come before <data.frame>, not after. Class: <data.frame/my_class>.
#> i If this object comes from a package, please report this error to the package author.
#> i Read our FAQ about creating vector types (`?vctrs::howto_faq_fix_scalar_type_error`) to learn more.
}\if{html}{\out{</div>}}

This is problematic as many tidyverse functions won’t work properly:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{dplyr::slice(my_df, 1)
#> Error in `vec_slice()`:
#> ! `x` must be a vector, not a <data.frame> object.
#> x Detected incompatible data frame structure. A data frame is normally treated as a vector, but an incompatible class ordering was detected. To be compatible, the subclass <my_class> must come before <data.frame>, not after. Class: <data.frame/my_class>.
#> i If this object comes from a package, please report this error to the package author.
#> i Read our FAQ about creating vector types (`?vctrs::howto_faq_fix_scalar_type_error`) to learn more.
}\if{html}{\out{</div>}}

It is generally not appropriate to declare your class to be a superclass
of another class. We generally consider this undefined behaviour (UB).
To fix these errors, you can simply change the construction of your data
frame class so that \code{"data.frame"} is a base class, i.e. it should come
last in the class vector:

\if{html}{\out{<div class="sourceCode r">}}\preformatted{class(my_df) <- c("my_class", "data.frame")

vctrs::obj_check_vector(my_df)

dplyr::slice(my_df, 1)
#>   x
#> 1 1
}\if{html}{\out{</div>}}
}
}
