I would expect that several math operations should always return values
with a class of numeric. If the input is defined with multiple classes,
however, the class attribute is preserved. I would think this may have
some unintended side-effects. Here's an example:
> sessionInfo()$R.version$version.string
[1] "R version 3.4.0 (2017-04-21)"
> x <- seq.int(5)
> class(x)
[1] "integer"
> class(log(x))
[1] "numeric"
> class(x) <- c("integer", "foo")
> log(x)
[1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379
attr(,"class")
[1] "integer" "foo"
> x + 0.5
[1] 1.5 2.5 3.5 4.5 5.5
attr(,"class")
[1] "integer" "foo"
I do see the note in ?Arithmetic that states "All attributes (including
class) are preserved if there is no coercion". Is this correct, or
should the returned value have an updated class of c("numeric", "foo")?
Should foo have its own methods to coerce the output to numeric?
Thanks,
Cole
Math ops behaviour with multiple classes
5 messages · Bert Gunter, Cole Beck, Hadley Wickham +1 more
I think you may be confusing (S3) class and ?mode.
x <- seq.int(1:3) class(x)
[1] "integer"
mode(x)
[1] "numeric"
class(x+.5) ## coercion
[1] "numeric"
mode(x+.5)
[1] "numeric" But note:
y <- as.integer(1) class(y)
[1] "integer"
class(y) <- "foo" mode(y)
[1] "numeric"
class(y+.5)
[1] "foo"
mode(y+.5)
[1] "numeric" And further:
class(y) <-c("foo","integer")
class(y+.5)
[1] "foo" "integer" So basically, the behavior seems to be: when the class attribute can be coerced to "numeric" by as.numeric(), it is. Otherwise it is left as is. Note that log is a primitive function not in the Ops groups, but has similar behavior. I would guess (corroboration or correction by more knowledgeable folks appreciated!) that this sort of semi-confusion with S3 classes was one of the motivators for adding the more rigorous S4 system. HTH Cheers, Bert Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
On Thu, Jun 8, 2017 at 9:40 AM, Cole Beck <cole.beck at vanderbilt.edu> wrote:
I would expect that several math operations should always return values with a class of numeric. If the input is defined with multiple classes, however, the class attribute is preserved. I would think this may have some unintended side-effects. Here's an example:
sessionInfo()$R.version$version.string
[1] "R version 3.4.0 (2017-04-21)"
x <- seq.int(5) class(x)
[1] "integer"
class(log(x))
[1] "numeric"
class(x) <- c("integer", "foo")
log(x)
[1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379 attr(,"class") [1] "integer" "foo"
x + 0.5
[1] 1.5 2.5 3.5 4.5 5.5
attr(,"class")
[1] "integer" "foo"
I do see the note in ?Arithmetic that states "All attributes (including
class) are preserved if there is no coercion". Is this correct, or should
the returned value have an updated class of c("numeric", "foo")? Should foo
have its own methods to coerce the output to numeric?
Thanks,
Cole
______________________________________________ R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see https://stat.ethz.ch/mailman/listinfo/r-help PLEASE do read the posting guide http://www.R-project.org/posting-guide.html and provide commented, minimal, self-contained, reproducible code.
Thanks Bert, I think we agree on the current behaviour, but I'm still not sure if it's desirable. The mode isn't used for method dispatch. In the following example, I have to write `log.foo` in order for the correct method to be called.
x <- seq.int(5)
class(x) <- c("integer", "foo")
half <- function(x) UseMethod("half")
half.default <- function(x) {
+ floor(x) / 2 + }
half.integer <- function(x) {
+ x %/% 2 + }
half(log(x)) # dispatches half.integer, not desired
[1] 0 0 0 0 0 attr(,"class") [1] "integer" "foo"
half(log(seq(5))) # dispatches half.default, as desired
[1] 0.0 0.0 0.5 0.5 0.5
log.foo <- function(x) {
+ res <- log(as.numeric(x))
+ class(res) <- c("numeric", "foo")
+ res
+ }
half(log(x)) # dispatches log.foo, then half.default, as desired
[1] 0.0 0.0 0.5 0.5 0.5 attr(,"class") [1] "numeric" "foo" Not only would I have to write `log.foo`, but I'd need to add my own `foo` methods for the Math and Ops groups. Using a different class system might be a better solution, but my preference would definitely be for the base functions to coerce the class to numeric (which it indeed does if there are not multiple classes). Cole
From: Bert Gunter [bgunter.4567 at gmail.com]
Sent: Thursday, June 08, 2017 4:45 PM
To: Beck, Cole
Cc: R-help
Subject: Re: [R] Math ops behaviour with multiple classes
Sent: Thursday, June 08, 2017 4:45 PM
To: Beck, Cole
Cc: R-help
Subject: Re: [R] Math ops behaviour with multiple classes
I think you may be confusing (S3) class and ?mode.
> x <- seq.int(1:3)
> class(x)
[1] "integer"
> mode(x)
[1] "numeric"
> class(x+.5) ## coercion
[1] "numeric"
> mode(x+.5)
[1] "numeric"
But note:
> y <- as.integer(1)
> class(y)
[1] "integer"
> class(y) <- "foo"
> mode(y)
[1] "numeric"
> class(y+.5)
[1] "foo"
> mode(y+.5)
[1] "numeric"
And further:
> class(y) <-c("foo","integer")
> class(y+.5)
[1] "foo" "integer"
So basically, the behavior seems to be: when the class attribute can
be coerced to "numeric" by as.numeric(), it is. Otherwise it is left
as is.
Note that log is a primitive function not in the Ops groups, but has
similar behavior.
I would guess (corroboration or correction by more knowledgeable folks
appreciated!) that this sort of semi-confusion with S3 classes was one
of the motivators for adding the more rigorous S4 system.
HTH
Cheers,
Bert
Bert Gunter
"The trouble with having an open mind is that people keep coming along
and sticking things into it."
-- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
On Thu, Jun 8, 2017 at 9:40 AM, Cole Beck <cole.beck at vanderbilt.edu> wrote:
> I would expect that several math operations should always return values with
> a class of numeric. If the input is defined with multiple classes, however,
> the class attribute is preserved. I would think this may have some
> unintended side-effects. Here's an example:
>
>> sessionInfo()$R.version$version.string
> [1] "R version 3.4.0 (2017-04-21)"
>> x <- seq.int(5)
>> class(x)
> [1] "integer"
>> class(log(x))
> [1] "numeric"
>> class(x) <- c("integer", "foo")
>> log(x)
> [1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379
> attr(,"class")
> [1] "integer" "foo"
>> x + 0.5
> [1] 1.5 2.5 3.5 4.5 5.5
> attr(,"class")
> [1] "integer" "foo"
>
> I do see the note in ?Arithmetic that states "All attributes (including
> class) are preserved if there is no coercion". Is this correct, or should
> the returned value have an updated class of c("numeric", "foo")? Should foo
> have its own methods to coerce the output to numeric?
>
> Thanks,
> Cole
>
> ______________________________________________
> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.
On Thu, Jun 8, 2017 at 2:45 PM, Bert Gunter <bgunter.4567 at gmail.com> wrote:
I think you may be confusing (S3) class and ?mode.
Your point is well made, but to be precise, I think you should talk about the "type of" an object, not it's mode. mode() is a wrapper around typeof(), designed (I believe) for S compatibility. Hadley
Cole, that cow left the barn decades ago. You really should read Patrick Burns' discussion of the history of R [1]. [1] http://www.burns-stat.com/documents/presentations/inferno-ish-R/
Sent from my phone. Please excuse my brevity.
On June 8, 2017 3:48:23 PM PDT, "Beck, Cole" <cole.beck at Vanderbilt.Edu> wrote:
>Thanks Bert, I think we agree on the current behaviour, but I'm still
>not sure if it's desirable. The mode isn't used for method dispatch.
>In the following example, I have to write `log.foo` in order for the
>correct method to be called.
>
>> x <- seq.int(5)
>> class(x) <- c("integer", "foo")
>> half <- function(x) UseMethod("half")
>> half.default <- function(x) {
>+ floor(x) / 2
>+ }
>> half.integer <- function(x) {
>+ x %/% 2
>+ }
>> half(log(x)) # dispatches half.integer, not desired
>[1] 0 0 0 0 0
>attr(,"class")
>[1] "integer" "foo"
>> half(log(seq(5))) # dispatches half.default, as desired
>[1] 0.0 0.0 0.5 0.5 0.5
>> log.foo <- function(x) {
>+ res <- log(as.numeric(x))
>+ class(res) <- c("numeric", "foo")
>+ res
>+ }
>> half(log(x)) # dispatches log.foo, then half.default, as desired
>[1] 0.0 0.0 0.5 0.5 0.5
>attr(,"class")
>[1] "numeric" "foo"
>
>Not only would I have to write `log.foo`, but I'd need to add my own
>`foo` methods for the Math and Ops groups. Using a different class
>system might be a better solution, but my preference would definitely
>be for the base functions to coerce the class to numeric (which it
>indeed does if there are not multiple classes).
>
>Cole
>________________________________________
>From: Bert Gunter [bgunter.4567 at gmail.com]
>Sent: Thursday, June 08, 2017 4:45 PM
>To: Beck, Cole
>Cc: R-help
>Subject: Re: [R] Math ops behaviour with multiple classes
>
>I think you may be confusing (S3) class and ?mode.
>
>> x <- seq.int(1:3)
>> class(x)
>[1] "integer"
>> mode(x)
>[1] "numeric"
>> class(x+.5) ## coercion
>[1] "numeric"
>> mode(x+.5)
>[1] "numeric"
>
>But note:
>
>> y <- as.integer(1)
>> class(y)
>[1] "integer"
>> class(y) <- "foo"
>> mode(y)
>[1] "numeric"
>> class(y+.5)
>[1] "foo"
>> mode(y+.5)
>[1] "numeric"
>
>And further:
>
>> class(y) <-c("foo","integer")
>> class(y+.5)
>[1] "foo" "integer"
>
>So basically, the behavior seems to be: when the class attribute can
>be coerced to "numeric" by as.numeric(), it is. Otherwise it is left
>as is.
>
>Note that log is a primitive function not in the Ops groups, but has
>similar behavior.
>
>I would guess (corroboration or correction by more knowledgeable folks
>appreciated!) that this sort of semi-confusion with S3 classes was one
>of the motivators for adding the more rigorous S4 system.
>
>HTH
>
>Cheers,
>Bert
>
>
>Bert Gunter
>
>"The trouble with having an open mind is that people keep coming along
>and sticking things into it."
>-- Opus (aka Berkeley Breathed in his "Bloom County" comic strip )
>
>
>On Thu, Jun 8, 2017 at 9:40 AM, Cole Beck <cole.beck at vanderbilt.edu>
>wrote:
>> I would expect that several math operations should always return
>values with
>> a class of numeric. If the input is defined with multiple classes,
>however,
>> the class attribute is preserved. I would think this may have some
>> unintended side-effects. Here's an example:
>>
>>> sessionInfo()$R.version$version.string
>> [1] "R version 3.4.0 (2017-04-21)"
>>> x <- seq.int(5)
>>> class(x)
>> [1] "integer"
>>> class(log(x))
>> [1] "numeric"
>>> class(x) <- c("integer", "foo")
>>> log(x)
>> [1] 0.0000000 0.6931472 1.0986123 1.3862944 1.6094379
>> attr(,"class")
>> [1] "integer" "foo"
>>> x + 0.5
>> [1] 1.5 2.5 3.5 4.5 5.5
>> attr(,"class")
>> [1] "integer" "foo"
>>
>> I do see the note in ?Arithmetic that states "All attributes
>(including
>> class) are preserved if there is no coercion". Is this correct, or
>should
>> the returned value have an updated class of c("numeric", "foo")?
>Should foo
>> have its own methods to coerce the output to numeric?
>>
>> Thanks,
>> Cole
>>
>> ______________________________________________
>> R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>> https://stat.ethz.ch/mailman/listinfo/r-help
>> PLEASE do read the posting guide
>http://www.R-project.org/posting-guide.html
>> and provide commented, minimal, self-contained, reproducible code.
>
>______________________________________________
>R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see
>https://stat.ethz.ch/mailman/listinfo/r-help
>PLEASE do read the posting guide
>http://www.R-project.org/posting-guide.html
>and provide commented, minimal, self-contained, reproducible code.