From h.wickham at gmail.com  Fri Aug 12 18:31:12 2016
From: h.wickham at gmail.com (Hadley Wickham)
Date: Fri, 12 Aug 2016 11:31:12 -0500
Subject: [Rd] ifelse() woes ... can we agree on a ifelse2() ?
In-Reply-To: <22445.44128.203938.13068@stat.math.ethz.ch>
References: <22437.61893.901739.933100@stat.math.ethz.ch>
	<deb934cc-d781-8011-d29b-f1cbcf60407e@gmail.com>
	<22445.44128.203938.13068@stat.math.ethz.ch>
Message-ID: <CABdHhvEtBu5=zPuhXNxtTH_5vBbmqbr-U0j3WH9ftjUeABqEWA@mail.gmail.com>

>     >> One possibility would also be to consider  a "numbers-only" or
>     >> rather "same type"-only {e.g., would also work for characters}
>     >> version.
>
>     > I don't know what you mean by these.
>
> In the mean time, Bob Rudis mentioned   dplyr::if_else(),
> which is very relevant, thank you Bob!
>
> As I have found, that actually works in such a "same type"-only way:
> It does not try to coerce, but gives an error when the classes
> differ, even in this somewhat debatable case :
>
>    > dplyr::if_else(c(TRUE, FALSE), 2:3, 0+10:11)
>    Error: `false` has type 'double' not 'integer'
>    >
>
> As documented, if_else() is clearly stricter than ifelse()
> and e.g., also does no recycling (but of length() 1).

I agree that if_else() is currently too strict - it's particularly
annoying if you want to replace some values with a missing:

x <- sample(10)
if_else(x > 5, NA, x)
#  Error: `false` has type 'integer' not 'logical'

But I would like to make sure that this remains an error:

if_else(x > 5, x, "BLAH")

Because that seems more likely to be a user error (but reasonable
people might certainly believe that it should just work)

dplyr is more accommodating in other places (i.e. in bind_rows(),
collapse() and the joins) but it's surprisingly hard to get all the
details right. For example, what should the result of this call be?

if_else(c(TRUE, FALSE), factor(c("a", "b")), factor(c("c", "b"))

Strictly speaking I think you could argue it's an error, but that's
not very user-friendly. Should it be a factor with the union of the
levels? Should it be a character vector + warning? Should the
behaviour change if one set of levels is a subset of the other set?

There are similar issues for POSIXct (if the time zones are different,
which should win?), and difftimes (similarly for units).  Ideally
you'd like the behaviour to be extensible for new S3 classes, which
suggests it should be a generic (and for the most general case, it
would need to dispatch on both arguments).

Hadley

-- 
http://hadley.nz



[Rd] ifelse() woes ... can we agree on a ifelse2() ?
Hadley Wickham