Reputation: 5003
In R user-defined operators are allowed, but it seems that only % %
like operators are accepted. Is it possible to walk around this restriction to define operators like, for example, >>
, or something that is not like % %
?
The operator must be a real operator so that we can use it like 1 >> 2
and do not have to use it like ">>"(1,2)
.
Upvotes: 13
Views: 898
Reputation: 545953
No. R only allows you to
`+`
or, indeed, `<-`
), and%…%
.These are the rules we have to play by. However, inside these rules all is fair game. For instance, we can redefine `+`
for character strings to perform concatenation, without destroying its normal meaning (addition):
`+`
# function (e1, e2) .Primitive("+")
This is the old definition, which we want to preserve for numbers:
`+.default` = .Primitive('+')
`+.character` = paste0`1
`+` = function (e1, e2) UseMethod('+')
1 + 2
# [1] 3
'hello' + 'world'
# [1] "helloworld"
This exploits the S3 class system in R to make `+`
fully generic on the type of its first argument.
The list of operators that can thus be redefined is quite eclectic. At first count, it contains the following operators:
+
,-
,*
,/
,^
,&
,|
,:
,::
,:::
,$
,=
,<-
,<<-
,==
,<
,<=
,>
,>=
,!=
,~
,&&
,||
,!
,?
,@
,:=
,(
,{
,[
,[[
(From the {modules} source code.)
In this list, one particular operator is noteworthy: `:=`
is an overridable operator (and {data.table} for example uses it) but unlike most the other operators in this list it has no default implementation.
Similarly, you can define assignment versions of pretty much every operator, not just those with a predefined assignment (such as `[<-`
). For example, `(<-`
and `{<-`
are also missing a default implementation. This is why the following code fails:
a = 1
(a) = 2
# Error in (a) = 2 : could not find function "(<-"
{a} = 3
# Error in { : could not find function "{<-"
But the code can be made to work by defining the operators:
`(<-` = `{<-` = function (x, value) value
The same works for every function, including almost all operators1, and even control structures (see the comments below this answer).
By contrast, `**`
isn’t a real operator: it’s a syntactic alias for `^`
. Users can define their own `**`
function but it can’t be called via the code a ** b
so it’s not an overridable operator (except via overriding `^`
).
In the same vein, you can override ->
(only) by redefining <-
. This seems like it would rarely make sense — but at least one good example of this exists, to define less verbose lambdas:
> sapply(1 : 4, x -> 2 * x)
[1] 2 4 6 8
1 The only exception are the assignment operators: You cannot change the meaning of a <- b <- c
by redefining `<-<-`
(and the same for `=<-`
, `<<-`
and `:=`
), due to the language’s operator precedence and associativity rules. However, the following code invokes both `(<-`
and `<-<-`
, and fails if either of these is not defined:
(a <- b) <- c
Messed up.
Upvotes: 20
Reputation: 99361
You can do things like this, but you may want to assign these objects to a new environment to be safe.
> "^" <- function(x, y) `-`(x, y) ## subtract y from x
> 5 ^ 3
# [1] 2
> "?" <- function(x, y) sum(x, y) ## add x and y
> 5 ? 5
# [1] 10
Upvotes: 5