Reputation: 18585
I'm creating a S4 object of the money class in the following manner:
# Create class ------------------------------------------------------------
# Create S4 class object holding money and export to generator function
setClass(Class = "money",
slots = list(currency = "character",
value = "numeric")) -> money
For which I'm later defining the show method:
# Methods -----------------------------------------------------------------
# Create show method
setMethod("show",
"money",
function(object) {
cat(switch(object@currency,
GBP = intToUtf8(163)),
format(
x = round(object@value, 2),
trim = TRUE,
big.mark = ",",
big.interval = 3
),
sep = "")
})
So far it works as promised:
# Create test object
tst_fig <- new(Class = "money",
value = 1e6,
currency = "GBP")
# Show the object
tst_fig
# £1,000,000
I would like to enable basic arithmetic on that object:
>> tst_fig + 1e6
Error in tst_fig + 1000000 : non-numeric argument to binary operator
> tst_fig + 1e6
# £2,000,000
Naturally this is won't work:
>> setMethod("+",
... "money",
... function(object, x) {
... object@value + x
... })
Error in conformMethod(signature, mnames, fnames, f, fdef, definition) :
in method for ‘+’ with signature ‘e1="money"’: formal arguments (e1 = "money", e2 = "money") omitted in the method definition cannot be in the signature
There is a similar excellent answer provided by @Roland on implementing money class in S3; in the context of this question I'm interested in creating S4 class that would behave in a similar manner without any specific reason other than curiosity. The key requirements is that isS4()
on that object returns TRUE
.
It prints like nicely formatted money but permits all operations the one could do on a common numeric.
Upvotes: 3
Views: 247
Reputation: 19960
I came across how to do this in my own question here. I have generally used the setMethod('Arith')
approach as it is more concise when you intend to implement several operations. If you search the documentation ?Arith
you will see that it list the different operations as well as other S4 group generics.
As the error suggests you need to have e1
and e2
defined for Arith
methods. In your specific case the following works.
Note - to get your desired output (i.e. a money
class object) you will need to create a new money
object.
setMethod("+",
c(e1="money", e2="numeric"),
function(e1, e2){
new(Class = "money", value = e1@value + e2, currency = e1@currency)
}
)
tst_fig + 1e6
[1] £2e+06
However, as I said, you probably want the more general, concise version which uses .Generic
to interpret the Arith
method you are using.
setMethod("Arith",
c(e1="money", e2="numeric"),
function(e1, e2)
{
op = .Generic[[1]]
switch(op,
`+` = return(new(Class = "money", value = e1@value + e2, currency = e1@currency))
)
}
)
Upvotes: 4