1#' Missing values
2#'
3#' @description
4#'
5#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("questioning")}
6#'
7#' Missing values are represented in R with the general symbol
8#' `NA`. They can be inserted in almost all data containers: all
9#' atomic vectors except raw vectors can contain missing values. To
10#' achieve this, R automatically converts the general `NA` symbol to a
11#' typed missing value appropriate for the target vector. The objects
12#' provided here are aliases for those typed `NA` objects.
13#'
14#'
15#' @details
16#'
17#' Typed missing values are necessary because R needs sentinel values
18#' of the same type (i.e. the same machine representation of the data)
19#' as the containers into which they are inserted. The official typed
20#' missing values are `NA_integer_`, `NA_real_`, `NA_character_` and
21#' `NA_complex_`. The missing value for logical vectors is simply the
22#' default `NA`. The aliases provided in rlang are consistently named
23#' and thus simpler to remember. Also, `na_lgl` is provided as an
24#' alias to `NA` that makes intent clearer.
25#'
26#' Since `na_lgl` is the default `NA`, expressions such as `c(NA, NA)`
27#' yield logical vectors as no data is available to give a clue of the
28#' target type. In the same way, since lists and environments can
29#' contain any types, expressions like `list(NA)` store a logical
30#' `NA`.
31#'
32#'
33#' @section Life cycle:
34#'
35#' These shortcuts might be moved to the vctrs package at some
36#' point. This is why they are marked as questioning.
37#'
38#' @keywords internal
39#' @examples
40#' typeof(NA)
41#' typeof(na_lgl)
42#' typeof(na_int)
43#'
44#' # Note that while the base R missing symbols cannot be overwritten,
45#' # that's not the case for rlang's aliases:
46#' na_dbl <- NA
47#' typeof(na_dbl)
48#' @name missing
49NULL
50
51#' @rdname missing
52#' @export
53na_lgl <- NA
54#' @rdname missing
55#' @export
56na_int <- NA_integer_
57#' @rdname missing
58#' @export
59na_dbl <- NA_real_
60#' @rdname missing
61#' @export
62na_chr <- NA_character_
63#' @rdname missing
64#' @export
65na_cpl <- NA_complex_
66
67
68#' Test for missing values
69#'
70#' @description
71#'
72#' \Sexpr[results=rd, stage=render]{rlang:::lifecycle("questioning")}
73#'
74#' `are_na()` checks for missing values in a vector and is equivalent
75#' to [base::is.na()]. It is a vectorised predicate, meaning that its
76#' output is always the same length as its input. On the other hand,
77#' `is_na()` is a scalar predicate and always returns a scalar
78#' boolean, `TRUE` or `FALSE`. If its input is not scalar, it returns
79#' `FALSE`. Finally, there are typed versions that check for
80#' particular [missing types][missing].
81#'
82#'
83#' @details
84#'
85#' The scalar predicates accept non-vector inputs. They are equivalent
86#' to [is_null()] in that respect. In contrast the vectorised
87#' predicate `are_na()` requires a vector input since it is defined
88#' over vector values.
89#'
90#' @param x An object to test
91#'
92#' @section Life cycle:
93#'
94#' These functions might be moved to the vctrs package at some
95#' point. This is why they are marked as questioning.
96#'
97#' @keywords internal
98#' @examples
99#' # are_na() is vectorised and works regardless of the type
100#' are_na(c(1, 2, NA))
101#' are_na(c(1L, NA, 3L))
102#'
103#' # is_na() checks for scalar input and works for all types
104#' is_na(NA)
105#' is_na(na_dbl)
106#' is_na(character(0))
107#'
108#' # There are typed versions as well:
109#' is_lgl_na(NA)
110#' is_lgl_na(na_dbl)
111#' @export
112are_na <- function(x) {
113  if (!is_atomic(x)) {
114    abort("`x` must be an atomic vector")
115  }
116  is.na(x)
117}
118#' @rdname are_na
119#' @export
120is_na <- function(x) {
121  is_scalar_vector(x) && is.na(x)
122}
123
124#' @rdname are_na
125#' @export
126is_lgl_na <- function(x) {
127  identical(x, na_lgl)
128}
129#' @rdname are_na
130#' @export
131is_int_na <- function(x) {
132  identical(x, na_int)
133}
134#' @rdname are_na
135#' @export
136is_dbl_na <- function(x) {
137  identical(x, na_dbl)
138}
139#' @rdname are_na
140#' @export
141is_chr_na <- function(x) {
142  identical(x, na_chr)
143}
144#' @rdname are_na
145#' @export
146is_cpl_na <- function(x) {
147  identical(x, na_cpl)
148}
149