Overloaded method value with alternatives

Hi,

I am playing around with defining operators in Scala. I have the following code:

object Hello {

  abstract class Element {
    def &(e: Zero)
    def &(e: One)
  }

  class Zero extends Element {
    override def &(e: Zero): Zero = this
    override def &(e: One): Zero = this
    override def toString: String = "0"
  }

  class One extends Element {
    override def &(e: Zero): Zero = e
    override def &(e: One): One = this
    override def toString: String = "1"
  }

  class Array2d {
    val plane = Array.fill[Element](4, 4){ new Zero }
    def setOne(x: Int, y: Int) = plane(y)(x) = new One()
    def dump(): Unit = { plane.foreach(line => {line.foreach(print); println();}); println(); }
    def &(other: Array2d) = {
      for (y <- 0 to plane.length - 1) {
        for (x <- 0 to plane(0).length - 1) {
          val a: Element = plane(y)(x)
          val b: Element = other.plane(y)(x)
          plane(y)(x) = a & b
        }
      }
    }
  }

  def main(args: Array[String]): Unit = {
    val zero = new Zero()
    val one = new One()

    println(zero & zero) // 0
    println(zero & one) // 0
    println(one & zero) // 0
    println(one & one) // 1

    val arr1 = new Array2d()
    val arr2 = new Array2d()

    arr1.setOne(0, 0)
    arr1.setOne(1, 1)
    arr1.dump()

    arr2.setOne(2, 2)
    arr2.setOne(3, 3)
    arr2.dump()

    arr1 & arr2
    arr1.dump()
  }

}

My & operator works fine for One and Zero. But I am not able to implement the & operator for 2d arrays filled with ones and zeros. How can I solve that? My IDE is complaining that plane(y)(x) = a & b is interpreted as a recursive method without result type. However, the & between a and b is supposed to be the Operator defined in the elements. :thinking:

That error almost always means that you’ve left off the return type of a function, and are expecting more type inference than the compiler can provide. In particular, this will usually cause a failure in recursive functions like Array2d.&, so you should explicitly say what the return type is.

Also – I’m really kind of surprised you’re not getting an error from Element.&. Since you aren’t specifying a return type, it’s probably inferring the return type to be Unit, which probably isn’t what you intend. You should definitely specify it there. In general, it’s a bad idea to have abstract members that don’t specify their type – you usually won’t get the expected behavior.

More generally, this code isn’t going to do what you want. You can’t leave out return types in the parent and just define them later – you have to specify them in terms of abstract types, and fill those in in the children. So I’m afraid this is actually more work than you were hoping for.

(NB: you might be able to get closer to what you’re looking for in Scala 3, with its new transparent functionality. But that’s all still very experimental and in-development.)