Scala - defining your own infix operators

Methods that take one argument can be written as infix statements in Scal. That is, adding *(other:C) = foo(this, other)

C to the class will allow us to write c1 * c2

instead of foo (c1, c2). But is there a way to define infix statements for existing classes that you cannot change?

eg. if i wanted to write c1 + c2

instead of xor(c1,c2)

where c1,c2:Array[Byte]

, i obviously cannot change the Array class.

I found this one and tried

implicit class Bytearray(a1:Array[Byte]) extends Anyval {
    def +(a2:Array[Byte]) = xor(a1,a2)
}

      

But that doesn't work ( c1 + c2

).

Type mismatch expected: String, Actual: Array [Byte]

I thought maybe the problem was what I was using +

, so I exchanged it for xor

 but c1 xor c2

only results in

Cannot resolve symbol xor

Any suggestions?

UPDATE

Interesting. I had class Foo

with object Foo

, defined below, containing an implicit class. This leads to the above errors.

However, deleting the object and adding the implicit class in trait BytearrayHandling

and then extending it ( class Foo extends BytearrayHandling

) seems to work. Why is this?

+3


source to share


2 answers


It should be straight forward with normal extension method declarations:

implicit class ByteArrayOps(private val a1: Array[Byte]) extends AnyVal {
  def + (a2: Array[Byte]): Array[Byte] = 
    (a1 zip a2).map { case (x, y) => (x ^ y).toByte }
}

"foo".getBytes + "bar".getBytes  // Array(4, 14, 29)

      


However, remember that sometimes you run into this:

Type mismatch, expected: String, actual: X

It has to do with implicit translation, which allows you to do +

anything by converting it to String. I'm up try to understand how to deactivate it. It will finally go into Scala 2.12 if I'm not mistaken.



As eugenger pointed out, this error message could indicate that you did not actually import your extension method (implicit conversion). For example:

object MyStuff {
  implicit class ByteArrayOps(private val a1: Array[Byte]) extends AnyVal {
    def + (a2: Array[Byte]): Array[Byte] = 
      (a1 zip a2).map { case (x, y) => (x ^ y).toByte }
  }
}

"foo".getBytes + "bar".getBytes  // error

      

gives:

<console>:14: error: type mismatch;
 found   : Array[Byte]
 required: String
              "foo".getBytes + "bar".getBytes
                                     ^

      

because of this transformation Predef

. Then import MyStuff.ByteArrayOps

he works.

+6


source


You can do something like:

class ByteArray(self: Array[Byte]) {
  def +(other: Array[Byte]) = Array[Byte](1, 2, 3) // replace with your code
}

implicit def byteArrayPlus(self: Array[Byte]) = new ByteArray(self)

Array[Byte](0, 1, 2) + Array[Byte](0, 2, 3)

      



the last line of which should matter Array(1, 2, 3)

.

+1


source







All Articles