Compiler Bug?

91 views
Skip to first unread message

David Miguel Antunes

unread,
Sep 30, 2016, 11:03:43 AM9/30/16
to scala...@googlegroups.com
Hi,

When I run this code:
trait Animal
trait Cat extends Animal

trait TraitA[-A] { def xyz()(implicit args: A): Unit = println("TraitA")}
trait TraitB extends TraitA[Cat] {override def xyz()(implicit args: Cat): Unit = println("TraitB")}

class ClassA extends TraitA[Animal]
class ClassB extends ClassA with TraitB

object Test1 extends App {
val ref1: ClassB = new ClassB()
val ref2: TraitA[Cat] = ref1
ref1.xyz()(new Cat {})
ref2.xyz()(new Cat {})
}
I get this output:

[info] Running Test1 
TraitB
TraitA

Is this the expected behavior? or is this a bug? - if so is there a workaround?

Thanks!
David

Oliver Ruebenacker

unread,
Sep 30, 2016, 2:20:28 PM9/30/16
to David Miguel Antunes, scala...@googlegroups.com

     Hello,

  I would expect that in case of overriding of a method, the runtime type of an object should decide which implementation of the method is called, so this clearly seems like a compiler bug to me.

     Best, Oliver


--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

David Miguel Antunes

unread,
Sep 30, 2016, 2:56:32 PM9/30/16
to Oliver Ruebenacker, scala...@googlegroups.com

Yep, that's what I also thought...

Here's a reduced version of this behavior:
class Animal
class Cat extends Animal

trait TraitA[-A] {
def xyz(args: A): Unit = println("TraitA.xyz(...: A)")

}

trait TraitB extends TraitA[Cat] {
  override def xyz(args: Cat): Unit = println("TraitB.xyz(...: Cat)")
}

class ClassB extends TraitB with TraitA[Animal]

object Test1 extends App {
(new ClassB()).xyz(new Cat())
(new ClassB()).xyz(new Cat(): Animal)
(new ClassB(): TraitA[Cat]).xyz(new Cat {})
}
[info] Running Test1 
TraitB.xyz(...: Cat)
TraitA.xyz(...: A)
TraitA.xyz(...: A)

Thanks,
David

David Miguel Antunes

unread,
Sep 30, 2016, 4:20:09 PM9/30/16
to Oliver Ruebenacker, scala...@googlegroups.com

There's something I'm probably missing there, but this looks like it would require multiple dispatch to work
The plain old visitor does what's needed though:
trait AnimalVisitor[T] {

def visitDefault(animal: Animal): T

def visit(animal: Animal): T = visitDefault(animal)
def visit(animal: Cat): T = visitDefault(animal)
}

class Animal {
def accept[T](visitor: AnimalVisitor[T]): T = visitor.visit(this)
}
class Cat extends Animal {
override def accept[T](visitor: AnimalVisitor[T]): T = visitor.visit(this)
}

trait TraitA[-A <: Animal] {

def xyzVisitor() = new AnimalVisitor[Unit] {
def visitDefault(animal: Animal) = println("TraitA.xyz(...: A)")
}

def xyz(args: A): Unit = args.accept(xyzVisitor())

}

trait TraitB extends TraitA[Cat] {
  override def xyzVisitor() = new AnimalVisitor[Unit] {
def visitDefault(animal: Animal) = TraitB.super.xyzVisitor().visitDefault(animal)

override def visit(animal: Cat) = println("TraitB.xyz(...: Cat)")

}
}

class ClassB extends TraitB with TraitA[Animal]

object Test1 extends App {
(new ClassB()).xyz(new Cat())
  (new ClassB(): TraitA[Cat]).xyz(new Cat {})
}

Then again, maybe I'm missing something

Thanks,
David

Adriaan Moors

unread,
Sep 30, 2016, 5:56:41 PM9/30/16
to David Miguel Antunes, Oliver Ruebenacker, scala-user, scala-i...@googlegroups.com
Hi,

Nice puzzler! Something's not right, I agree. Let's poke around!

Let's first consider a smaller but slightly different version (the essential difference is that I dropped the empty first argument list, which changes things a bit before erasure, but compiles to the same bytecode):

trait A[-T] { def m(x: T): Any = "A" }
trait B extends A[String] { override def m(x: String): Any = "B" }

val o = new A[Any] with B
assert(o.m("") == (o: A[String]).m(""))

The bug seems to be that we let you get away with pretending those two definitions of m are overriding. In fact, they are overloaded. You can verify this by making A's version of m abstract, upon which the compiler realizes something's not right:

scala> trait A[-T] { def m(x: T): Any }
defined trait A

scala> trait B extends A[String] { override def m(x: String): Any = "B" }
defined trait B

scala> val o = new A[Any] with B
<console>:38: error: object creation impossible, since method m in trait A of type (x: Any)Any is not defined
(Note that T does not match String)
val o = new A[Any] with B
^

Your version is slightly more puzzling, since you have an additional first argument list, which should be the only argument list we consider for overloading (your version and mine erase to the same bytecode, though), which makes for the second bug illustrated by your example.

cheers
adriaan

Thanks,
David

To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.

David Miguel Antunes

unread,
Oct 1, 2016, 10:08:17 AM10/1/16
to Adriaan Moors, Oliver Ruebenacker, scala-user, scala-i...@googlegroups.com
Hi,

Just another version of the problem, which may be simpler to read:
class Animal
class Cat extends Animal

trait Writer[-T] {
def write(args: T) = println("Writer.write(...: T)")
}

trait AnimalWriter extends Writer[Animal] {
override def write(args: Animal) = println("AnimalWriter.write(...: Animal)")
}

trait CatWriter extends Writer[Cat] {
override def write(args: Cat) = println("CatWriter.write(...: Cat)")
}

class MyWriter extends AnimalWriter with CatWriter

object Test1 extends App {
(new MyWriter(): MyWriter).write(new Cat()) // Produces: "CatWriter.write(...: Cat)"
(new MyWriter(): CatWriter).write(new Cat()) // Produces: "CatWriter.write(...: Cat)"
(new MyWriter(): AnimalWriter).write(new Cat()) // Produces: "AnimalWriter.write(...: Animal)"
}

Cheers,
David

Thanks,
David

To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+unsubscribe@googlegroups.com.

Adriaan Moors

unread,
Oct 5, 2016, 12:04:00 PM10/5/16
to David Miguel Antunes, Oliver Ruebenacker, scala-user, scala-i...@googlegroups.com

Thanks,
David

To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.

Naftoli Gugenheim

unread,
Oct 9, 2016, 9:12:53 PM10/9/16
to scala-i...@googlegroups.com, David Miguel Antunes, Oliver Ruebenacker, scala-user
So the move away from JIRA has begun?

You received this message because you are subscribed to the Google Groups "scala-internals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-interna...@googlegroups.com.

Adriaan Moors

unread,
Oct 10, 2016, 2:52:26 PM10/10/16
to Naftoli Gugenheim, scala-i...@googlegroups.com, David Miguel Antunes, Oliver Ruebenacker, scala-user
For now, we're using github issues internally to see whether it would be feasible to do this at scale (I wouldn't say I've missed JIRA yet). 

Once 2.12.0 is out, I'd like to start a discussion in the Scala Center context on a plan to make JIRA read-only and standardize on github for issue tracking.
Reply all
Reply to author
Forward
0 new messages