Skip to content

Unexpected type erasing using higher-kinded type & currying #12246

Open
@y-yu

Description

@y-yu

reproduction steps

using Scala 2.13.4

  • Whole PoC code is https://gist.github.com/y-yu/2c5ff872b22acde4e1b3685a8ae015e8

    • Execute sbt run after download the files
  • There is a type erasing difference between two classes: B1 and B1

    package example
    
    trait A[B[_]]
     
    class B1(x: String, y: A[List])
    class B2(x: String)(y: A[List])
    • class B2 defined to take two parameters as multiple parameter lists
  • Their javap results are:

    $ javap target/scala-2.13/classes/example/B1.class 
    Compiled from "Main.scala"
    public class example.B1 {
      public example.B1(java.lang.String, example.A<scala.collection.immutable.List>);
    }
     
    $ javap target/scala-2.13/classes/example/B2.class 
    Compiled from "Main.scala"
    public class example.B2 {
      public example.B2(java.lang.String, example.A<?>);
    }
    • In B2 constructor, the type of the second argument is the erasured type: A<?>
  • We expect that B1 and B2 should be the same result

problem

  • We found this bihavior using Google Guice
    • Needless to say, it's very popular library
    • We use this for Play framework
  • This behavior is not good for DI wiring higer-kinded classes by Guice
    • We cannot use currying constructor if the constructor takes higher-kinded type arguments such like Monad instance
    • Since using Guice DI, we have to inject only our classes but also implicit parameters 😢
  • So we wish to resolve this bihavior 🙏

postscript

  • We pass the higher-kinded type parameter like this:
    class B3[F[_]](x: String)(y: A[F])
    • It's OK 🙆‍♀️ but I don't know why it was not erased 🤔
    $ javap -c example.B3
    Compiled from "Main.scala"
    public class example.B3<F> {
      public example.B3(java.lang.String, example.A<F>);
    }
  • @xuwei-k san tried it out in Scala3.0.0-M1
    $ javap target/scala-3.0.0-M1/classes/example/B1.class 
    Compiled from "Main.scala"
    public class example.B1 {
      public example.B1(java.lang.String, example.A<scala.collection.immutable.List<java.lang.Object>>);
    }
     
    $ javap target/scala-3.0.0-M1/classes/example/B2.class 
    Compiled from "Main.scala"
    public class example.B2 {
      public example.B2(java.lang.String, example.A<scala.collection.immutable.List<java.lang.Object>>);
    }
    • Why is java.lang.Object inserted as their type arguments? 🤔
    • Anyway both cases don't work well in Scala3.0.0-M1
    • Would it be better to report this to dotty repo too?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions