Converting from type A to type B creates third type (B/A)
Closed this issue · 2 comments
Hi. Not sure if this is a bug or a misinterpretation, on my part, of how the package is meant to be used...
How would I get the return value of 'to_sample' (below) to be of type Sample/Whole/numeric -- which is what I expected/hoped for -- rather than Sample/Milliseconds/Whole/numeric (see testthat results pasted below)?
Thanks.
Code
Whole(n) %::% numeric : numeric
Whole(n) %when% {
n >= 0
} %:=% {
floor(n)
}
Natural(n) %::% numeric : numeric
Natural(n) %when% {
is.count(n)
} %:=% {
n
}
Sample(n) %::% numeric : numeric
Sample(n) %:=%
Whole(n)
Milliseconds(n) %::% numeric : numeric
Milliseconds(n) %:=%
Whole(n)
SamplePerSecond(n) %::% numeric : numeric
SamplesPerSecond(n) %:=%
Natural(n)
to_sample(ms, sample_per_s) %::% Milliseconds : SamplesPerSecond : Sample
to_sample(ms, sample_per_s) %as% {
per_ms <-
0.001
floor(ms * sample_per_s * per_ms) %>% Sample()
}
Failing test result
> library("testthat")
>
> context("to_sample")
>
> thousand_per_second <-
+ SamplesPerSecond(1000)
>
>
> test_that("zero samples can be found in zero milliseconds", {
+ sample_duration <-
+ Milliseconds(0)
+
+ to_sample(sample_duration, thousand_per_second) %>%
+ expect_equal(Sample(0))
+ })
Error: Test failed: 'zero samples can be found in zero milliseconds'
.
not equal to Sample(0).
Classes differ: Sample/Milliseconds/Whole/numeric is not Sample/Whole/numeric
answer was to wrap the conversion return value in as.numeric()
Hi, the main issue is how R manages class information for binary operations. Essentially R is using the class of the first operand:
> thousand_per_second <- SamplesPerSecond(1000)
> sample_duration <- Milliseconds(0)
> sample_duration * thousand_per_second
[1] 0
attr(,"class")
[1] "Milliseconds" "Whole" "numeric"
> thousand_per_second * sample_duration
[1] 0
attr(,"class")
[1] "SamplesPerSecond" "Natural" "numeric"
So when you pass this result to Sample
, it's prepending the Sample
class to the existing class of the value. And is stripping all of the class information from the value, which is why that works.
FWIW, I generally don't create type hierarchies like this, as I don't think they are necessary. It probably explains why I haven't seen this situation before.