Operator Overloading

 

1 Introduction

Base comes with relational (==, !=, etc.), arithmetic (+, -, *, /, etc.), logical (&, |) and bit-wise (&, |) operators. ‘broadcast’ provides 2 ways to use these operators with broadcasting.

The first (and simple) way is to use the broadcaster() class, which comes with it’s own method dispatch for the above mentioned operators. This approach supports operator precedence, and for the average user, this is sufficient.

For example:


x <- array(1:20, c(4, 5))
y <- array(1:5 * 100, c(1, 5))
z <- array(20:1, c(4, 5))

broadcaster(x) <- TRUE
broadcaster(y) <- TRUE
broadcaster(z) <- TRUE

x + y / z
#>          [,1]     [,2]     [,3]     [,4]     [,5]
#> [1,] 6.000000 17.50000 34.00000 63.00000 142.0000
#> [2,] 7.263158 19.33333 37.27273 71.14286 184.6667
#> [3,] 8.555556 21.28571 41.00000 81.66667 269.0000
#> [4,] 9.882353 23.38462 45.33333 96.00000 520.0000
#> broadcaster

The second way is to use the large set ofbc. - functions. These offer much greater control and more operators than the previous method, and has less risk of running into conflicting methods. But it does not support operator precedence.

For example:

x <- array(1:20, c(4, 5))
y <- array(1:5 * 100, c(1, 5))
print(x)
#>      [,1] [,2] [,3] [,4] [,5]
#> [1,]    1    5    9   13   17
#> [2,]    2    6   10   14   18
#> [3,]    3    7   11   15   19
#> [4,]    4    8   12   16   20
print(y)
#>      [,1] [,2] [,3] [,4] [,5]
#> [1,]  100  200  300  400  500

bc.i(x, y, "gcd") # calculate greatest common divisor between x and y
#>      [,1] [,2] [,3] [,4] [,5]
#> [1,]    1    5    3    1    1
#> [2,]    2    2   10    2    2
#> [3,]    1    1    1    5    1
#> [4,]    4    8   12   16   20

 

2 Derived operators

There is no overload for xor(), as xor() is defined using the existing base relational and logical (or bit-wise, for type of raw) operators.

There is also no overload for the %d==%, %d!=%, etc. operators, as they too are defined using the existing base relational and logical operators.

 

3 Overloaded operators vs bc.* functions

Overloading the operators is primarily useful for ensuring mathematically correct operator precedence, and to reduce the amount of typing.
However, the many bc.* functions provide much greater control than the simple operators can provide.

For example:
The & and | operators provide logical AND and OR, respectively for all atomic types except type raw; for type raw, the & and | operators provide BIT-WISE AND and OR, respectively.
But what if you want to use logical AND/OR for raw arrays, or bit-wise AND/OR for integer arrays?
When using the overloaded operators, using logical AND/OR for type raw necessitates converting the vector/array to type logical, thus making a copy.
With the bc.*() functions, this is not necessary.
Want to use logical AND/OR? Use bc.b(), it supports several types including raw.
Want to use bit-wise AND/OR? Use bc.bit(), it supports not only raw, but integer as well.

The bc. functions also provides far more operations than the simple symbols can provide.
Like calculating the greatest common divisors between integers, string edit distance, and more.