Skip to content

Commit fe32780

Browse files
committed
Make min and max check sizes of x and ... for clear intent
1 parent ccca817 commit fe32780

File tree

3 files changed

+88
-1
lines changed

3 files changed

+88
-1
lines changed

R/type-vctr.R

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,19 @@ vec_cast_or_na <- function(x, to, ...) {
546546
#' @export
547547
min.vctrs_vctr <- function(x, ..., na.rm = FALSE) {
548548
if (dots_n(...) != 0L) {
549+
sizes <- list_sizes(list(x, ...))
550+
if (any(sizes != 1L)) {
551+
cli::cli_abort(c(
552+
"Can't use `...` unless {.arg x} and each of {.arg ...} are of size 1.",
553+
"i" = "Size of {.arg x} was {vec_size(x)}",
554+
"i" = "{cli::qty(rlang::dots_n(...))}
555+
Size{?s} of {.arg ...} {?was/were} {list_sizes(list(...))}",
556+
">" = "If you wanted a size-1 result with the overall {.fn min},
557+
use {.code min(c(<args>))}",
558+
">" = "If you wanted a vectorized/parallel {.fn pmin},
559+
use {.code pmin(<args>)}"
560+
), class = "vctrs_error_min_intent_uncertain")
561+
}
549562
x <- vec_c(x, ...)
550563
}
551564

@@ -571,6 +584,19 @@ min.vctrs_vctr <- function(x, ..., na.rm = FALSE) {
571584
#' @export
572585
max.vctrs_vctr <- function(x, ..., na.rm = FALSE) {
573586
if (dots_n(...) != 0L) {
587+
sizes <- list_sizes(list(x, ...))
588+
if (any(sizes != 1L)) {
589+
cli::cli_abort(c(
590+
"Can't use `...` unless {.arg x} and each of {.arg ...} are of size 1.",
591+
"i" = "Size of {.arg x} was {vec_size(x)}",
592+
"i" = "{cli::qty(rlang::dots_n(...))}
593+
Size{?s} of {.arg ...} {?was/were} {list_sizes(list(...))}",
594+
">" = "If you wanted a size-1 result with the overall {.fn max},
595+
use {.code max(c(<args>))}",
596+
">" = "If you wanted a vectorized/parallel {.fn pmax},
597+
use {.code pmax(<args>)}"
598+
), class = "vctrs_error_max_intent_uncertain")
599+
}
574600
x <- vec_c(x, ...)
575601
}
576602

tests/testthat/_snaps/type-vctr.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,39 @@
3737
A B C
3838
xxx xxx xxx
3939

40+
# `min` and `max` either combine `x` and `...` or abort (#1372)
41+
42+
Code
43+
min(rep(x, 5), y)
44+
Condition <vctrs_error_min_intent_uncertain>
45+
Error:
46+
! Can't use `...` unless `x` and each of `...` are of size 1.
47+
i Size of `x` was 5
48+
i Size of `...` was 1
49+
> If you wanted a size-1 result with the overall `min()`, use `min(c(<args>))`
50+
> If you wanted a vectorized/parallel `pmin()`, use `pmin(<args>)`
51+
52+
---
53+
54+
Code
55+
min(x, rep(y, 5), z)
56+
Condition <vctrs_error_min_intent_uncertain>
57+
Error:
58+
! Can't use `...` unless `x` and each of `...` are of size 1.
59+
i Size of `x` was 1
60+
i Sizes of `...` were 5 and 1
61+
> If you wanted a size-1 result with the overall `min()`, use `min(c(<args>))`
62+
> If you wanted a vectorized/parallel `pmin()`, use `pmin(<args>)`
63+
64+
---
65+
66+
Code
67+
max(rep(x, 5), y)
68+
Condition <vctrs_error_max_intent_uncertain>
69+
Error:
70+
! Can't use `...` unless `x` and each of `...` are of size 1.
71+
i Size of `x` was 5
72+
i Size of `...` was 1
73+
> If you wanted a size-1 result with the overall `max()`, use `max(c(<args>))`
74+
> If you wanted a vectorized/parallel `pmax()`, use `pmax(<args>)`
75+

tests/testthat/test-type-vctr.R

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,16 +632,41 @@ test_that("Summary generics behave identically to base for empty vctrs (#88)", {
632632
)
633633
})
634634

635-
test_that("methods combine `x` and `...` when generic expects them to (#1372)", {
635+
test_that("`min` and `max` either combine `x` and `...` or abort (#1372)", {
636636
x <- new_vctr(1)
637637
y <- new_vctr(3)
638+
z <- new_vctr(5)
638639

639640
expect_identical(min(x, y), x)
640641
expect_identical(min(y, x), x)
641642
expect_identical(max(x, y), y)
642643
expect_identical(max(y, x), y)
644+
645+
expect_identical(min(x, y, z), x)
646+
expect_identical(max(x, y, z), z)
647+
648+
expect_error(min(rep(x, 5), y), class = "vctrs_error_min_intent_uncertain")
649+
expect_error(min(x, rep(y, 5)), class = "vctrs_error_min_intent_uncertain")
650+
expect_error(min(rep(x, 0), y), class = "vctrs_error_min_intent_uncertain")
651+
expect_error(min(x, rep(y, 0)), class = "vctrs_error_min_intent_uncertain")
652+
expect_error(max(rep(x, 5), y), class = "vctrs_error_max_intent_uncertain")
653+
expect_error(max(x, rep(y, 5)), class = "vctrs_error_max_intent_uncertain")
654+
expect_error(max(rep(x, 0), y), class = "vctrs_error_max_intent_uncertain")
655+
expect_error(max(x, rep(y, 0)), class = "vctrs_error_max_intent_uncertain")
656+
657+
expect_snapshot(min(rep(x, 5), y), error = TRUE, cnd_class = TRUE)
658+
expect_snapshot(min(x, rep(y, 5), z), error = TRUE, cnd_class = TRUE)
659+
expect_snapshot(max(rep(x, 5), y), error = TRUE, cnd_class = TRUE)
660+
})
661+
662+
test_that("`range` combines `...` (#1372)", {
663+
x <- new_vctr(1)
664+
y <- new_vctr(3)
665+
z <- new_vctr(as.numeric(13:11))
666+
643667
expect_identical(range(x, y), c(x, y))
644668
expect_identical(range(y, x), c(x, y))
669+
expect_identical(range(x, y, z), c(x, z[[1]]))
645670
})
646671

647672
test_that("generic predicates return logical vectors (#251)", {

0 commit comments

Comments
 (0)