Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R: How to overload the `-` operator if you want use `-` in your 'overload' code?

Just for fun I am trying to overload the - in R so that running

some.string - n

will give me the some.string with the last n characters removed.

This is my code in R

`-` <- function(x,y) {
  minus <- force(`-`)
  if(typeof(x) == "character" & y >0) {
    return(substr(x,1,minus(nchar(x), as.integer(y))))
  } else {
    return(minus(x,y))
  }
}

"abc" - 2

However this seems to cause a an infinitely nested recursion. This is because every time minus is run it tries to run itself. But that's exactly what I am trying to prevent by assigning minus = - in the first place?

How do I avoid this endless recursion?

like image 913
xiaodai Avatar asked Sep 25 '14 06:09

xiaodai


People also ask

How do you overload an operator?

Operator Overloading in Binary Operators Here, + is a binary operator that works on the operands num and 9 . When we overload the binary operator for user-defined types by using the code: obj3 = obj1 + obj2; The operator function is called using the obj1 object and obj2 is passed as an argument to the function.

How do you overload cout?

To get cout to accept a Date object after the insertion operator, overload the insertion operator to recognize an ostream object on the left and a Date on the right. The overloaded << operator function must then be declared as a friend of class Date so it can access the private data within a Date object.

Which operator is overloaded by the OR () function in Python?

Which operator is overloaded by the __or__() function? Explanation: The function __or__() overloads the bitwise OR operator |.

Which of the following operator can be overloaded?

Which of the following operator can be overloaded? c) . Explanation: ?:, :: and . cannot be overloaded whereas == can be overloaded.


3 Answers

Along the lines of suggestion from @PatrickRoocks, make your own (S3 or S4) class and dispatch (rather than mask) on that.

`-.my` = function(e1, e2) substr(e1, 1, nchar(e1) - e2)

x = c('all', 'the', 'world')
class(x) = 'my'
x - 1
## [1] "al"   "th"   "worl"
## attr(,"class")
## [1] "my"

See also ?Ops in the base (for S3) or methods (S4) package, which defines a 'group generic'

 Ops.my = function(e1, e2) {
     FUN = get(.Generic, envir = parent.frame(), mode = "function")
     substr(e1, 1, FUN(nchar(e1), e2))
}

to implement (in a nonsensical way, for the specific function above -- substr(x, 1, nchar(x) + 2) doesn't make sense), x - 1, x + 1, x / 2, etc. in a single definition.

The S4 version (sort of like @Sebastian, and from here) is

.My = setClass("My", contains="character")
setMethod("Arith", c("My", "numeric"), function(e1, e2) {
    substr(e1, 1, callGeneric(nchar(e1), e2))
})

with

> .My(c("all", "the", "world")) - 1
An object of class "My"
[1] "al"   "th"   "worl"
like image 131
Martin Morgan Avatar answered Oct 30 '22 19:10

Martin Morgan


Here is another solution using S4 method dispatch. The dispatch will be more elegant compared to using if-else structures and you do not have to mask the primitive function -. However for primitive functions it appears that it is not allowed to define methods for atomic data types. Hence, I needed to define a new class "lastCharacters". Actually this makes the last line a bit more readible as the intention of the code is clear...

lastCharacters <- setClass("lastCharacters", contains = "numeric")

setMethod("-", 
          signature(e1 = "character", e2 = "lastCharacters"),
          function(e1, e2) {
            substr(e1, 1, nchar(e1) - as.integer(e2))
          })

"abc" - lastCharacters(2)
like image 31
Sebastian Avatar answered Oct 30 '22 20:10

Sebastian


You can use .Primitive("-") to avoid an endless loop. This should work:

`-` <- function(x,y) {
  if(typeof(x) == "character" & y >0) {
    return(substr(x, 1, nchar(x) - as.integer(y)))
  } else {
    .Primitive("-")(x, y)
  }
}

Closer to your original idea is to define minus <- get("-", envir=baseenv()):

`-` <- function(x,y) {
  minus <- get("-", envir=baseenv())
  if(typeof(x) == "character" & y >0) {
    return(substr(x,1,minus(nchar(x), as.integer(y))))
  } else {
    return(minus(x,y))
  }
}
like image 22
shadow Avatar answered Oct 30 '22 18:10

shadow