Issue with calling Scala code from Java

Trying to wrap my head around an issue I get calling some Scala code from Java (dummified example):

// $ cat Bar.scala:

trait Bar[F] {
          def f  : F
    final def bar: F = f // the real life example is more involved here
}

// ==================================================
//$ cat Foo.scala:

class Foo() extends Bar[Foo] {
    override def f: Foo = this
}


// ==================================================
//$ cat Baz.java:

class Baz {
    public static void main(String args[]) {
    //  Foo foo =       new Foo().bar();  // compilation error: incompatible types: Object cannot be converted to Foo
        Foo foo = (Foo)(new Foo().bar()); // compiles
    }
}

Why is the cast to (Foo) necessary? The .bar method is supposed to return an F, which in the context of Foo is necessarily a Foo (?)

Notes:

  • If I call .f() directly instead of .bar(), the cast is no longer necessary
  • I wrote a Java-only version which doesn’t seem to need the cast (compiles): See gist - hopefully it is indeed equivalent
  • If I change the example to using an F-bounded quantification ([F <: Bar[F]]), the message changes from complaining about having a “Object” to complaining about a “Bar”

Any insight would be appreciated :slight_smile:

Anthony

EDIT: using scala 2.12.13 for the above example

1 Like

My first thought was “type erasure” but having used Scala 3.1.1 to compile Bar and Foo, Java 16 compiled

Foo foo = new Foo().bar();

without complaints. So maybe Scala 2.12 is to blame?

1 Like

Interesting… I just tested with 2.13.4 and got the compilation error too

PS: my javac is 1.8.0_161

What about 2.13.8? 2.13.4 is pretty old, too.

Just tried it with 2.13.8: same problem.

To be sure this is what I use to test it: rm *.class || :; ~/bin/scala/2.13.8/bin/scalac Bar.scala Foo.scala && javac -cp ~/bin/scala/2.13.8/lib/scala-library.jar:. Baz.java && java -cp ~/bin/scala/2.13.8/lib/scala-library.jar:. Baz

which gets me:

Baz.java:3: error: incompatible types: Object cannot be converted to Foo
      Foo foo =       new Foo().bar(); // error: incompatible types: Object cannot be converted to Foo
                                   ^
1 error
1 Like

Any reasons to using the CLI commands directly instead of using a build tool like sbt?

Mostly to keep the example minimal

1 Like

Any reason to use CLI commands which aren’t named something-cli?

I think they are converging on scala-cli.

It’s nice to get a small repo as a repro, but usually they are not minimal. If I try to update the scala version, then there is often a missing dependency. So I expect scala-cli to usher in a new era of reproducible snippets.

For such a minimal minimalization, I didn’t even need scala-library.jar on the path.

It would be nice if I could just run scala and it does the obvious thing (compile sources in cwd).

Also compile java sources. Was that not obvious enough?

So I think I will report it as an issue in Issues · scala/bug · GitHub, as it seems like it’s legitimate problem.

Thanks all for the help!

PS: reported on as Unexpected compilation error while calling Scala from Java · Issue #12556 · scala/bug · GitHub