|
54 | 54 | #' programmatically. |
55 | 55 | #' @return Either `from` coerced to class `to`, or an error if the coercion |
56 | 56 | #' is not possible. |
| 57 | +#' @seealso [convert_lazy()] for a non-strict variant that leaves `from` |
| 58 | +#' unchanged when it already inherits from `to`. |
57 | 59 | #' @export |
58 | 60 | #' @examples |
59 | 61 | #' Foo1 := new_class(properties = list(x = class_integer)) |
@@ -138,6 +140,45 @@ convert <- function(from, to, ...) { |
138 | 140 | } |
139 | 141 | } |
140 | 142 |
|
| 143 | +#' Non-strict conversion |
| 144 | +#' |
| 145 | +#' @description |
| 146 | +#' `convert_lazy()` is a non-strict variant of [convert()] that guarantees |
| 147 | +#' that the result inherits from `to`, without forcing `from` to become an exact |
| 148 | +#' instance of `to`, i.e. it never upcasts. |
| 149 | +#' |
| 150 | +#' @inheritParams convert |
| 151 | +#' @return `from`, unchanged, if it already inherits from `to`; otherwise the |
| 152 | +#' result of `convert(from, to, ...)`. |
| 153 | +#' @seealso [convert()] for the strict variant that always returns an exact |
| 154 | +#' instance of `to`. |
| 155 | +#' @export |
| 156 | +#' @examples |
| 157 | +#' Foo1 := new_class(properties = list(x = class_integer)) |
| 158 | +#' Foo2 := new_class(Foo1, properties = list(y = class_double)) |
| 159 | +#' |
| 160 | +#' # `convert()` upcasts by stripping the extra properties of `from`: |
| 161 | +#' convert(Foo2(x = 1L, y = 2), to = Foo1) |
| 162 | +#' |
| 163 | +#' # `convert_lazy()` never upcasts: because the object already inherits from |
| 164 | +#' # Foo1, it's returned unchanged, keeping `y`: |
| 165 | +#' convert_lazy(Foo2(x = 1L, y = 2), to = Foo1) |
| 166 | +#' |
| 167 | +#' # When `from` doesn't inherit from `to`, `convert_lazy()` falls back to |
| 168 | +#' # `convert()`, so it can still downcast or coerce to a base type: |
| 169 | +#' convert_lazy(Foo1(x = 1L), to = Foo2, y = 2.5) |
| 170 | +#' convert_lazy(1.5, to = class_character) |
| 171 | +convert_lazy <- function(from, to, ...) { |
| 172 | + to <- as_class(to) |
| 173 | + check_can_inherit(to) |
| 174 | + |
| 175 | + if (class_inherits(from, to)) { |
| 176 | + from |
| 177 | + } else { |
| 178 | + convert(from, to, ...) |
| 179 | + } |
| 180 | +} |
| 181 | + |
141 | 182 | # Resolve the `convert()` method for converting `from` to `to`, or `NULL` if |
142 | 183 | # there's no registered method (so `convert()` falls back to its defaults). |
143 | 184 | # See convert docs for the motivation for this design. |
|
0 commit comments