Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Scala3 type bug when used with java #16029

Discussion options

In a new Scala3 types system, if I write two simple classes in Scala as follows

final class ScalaClass(val in: "Hello") {
 override def toString: String = s"ScalaClass($in)"
 def printAllCharacters(): Unit = in.foreach(println)
}

&

final class ScalaClass1(private var in: "Hello") {
 def getIn: "Hello" = in
 def setIn(in1: "Hello"): Unit = {
 in = in1
 }
 def printAllCharacters(): Unit = in.foreach(println)
 override def toString: String = s"ScalaClass1($in)"
}

And then use them in Java as well as in Scala would produce different output, for example:

public class JavaClass {
 public static void main(String[] args) {
 ScalaClass scalaClass = new ScalaClass("jhjhjhjh");
 System.out.println(scalaClass);
 System.out.println(">>>>>>>>>>>>>>>>>>>>>>>");
 ScalaClass1 scalaClass1 = new ScalaClass1("sasas");
 System.out.println(scalaClass1);
 System.out.println(scalaClass1.getIn());
 scalaClass1.setIn("asasasas");
 System.out.println(scalaClass1.getIn());
 System.out.println(scalaClass1);
 }
}

Would will produce output as:

ScalaClass(Hello)
>>>>>>>>>>>>>>>>>>>>>>>
ScalaClass1(sasas)
sasas
Hello
ScalaClass1(Hello)

And running the same in Scala would be something different:

@main def runScalaClass(): Unit = {
 // val a = ScalaClass("As") Compilation Error
 val a = ScalaClass("Hello")
 println(a)
}

&

@main def runScalaMain1(): Unit = {
 // val a = new ScalaClass1("asas") Compilation Error
 val a = new ScalaClass1("Hello")
 println(a)
 println(a.getIn)
 // a.setIn("sss") Compilation Error
 a.setIn("Hello")
 println(a)
}

So the same simple API works differently for Java as well as in Scala.

  • What if someone needs to write simple Scala classes that are interoperable with Java?
  • In this case, the same code should produce identical results when used with Java and Scala, which is not the case!
  • Such a typing system makes the project more prone to developer bugs in projects that contain code that combines Java and Scala.
  • Hard to understand, for example, someone reading the code would see a simple Scala class with getter and setter but when run through java: getter, setter, and constructor all three produce unexpected results, resulting in confusion between what is written and what is output.
You must be logged in to vote

A Scalafix rule could lint features not supported in Java or known interop issues.

At a glance, I don't see that such a rule has been written at https://scalacenter.github.io/scalafix/docs/rules/community-rules.html

Replies: 3 comments 1 reply

Comment options

The above two classes ScalaClass & ScalaClass1 would look something like this

import java.lang.invoke.SerializedLambda;
import scala.Function1;
import scala.Predef$;
import scala.collection.StringOps$;
public final class ScalaClass
{
 private final String in;
 
 public ScalaClass(final String in) {
 this.in = in;
 }
 
 public String in() {
 return this.in;
 }
 
 @Override
 public String toString() {
 return new StringBuilder(17).append("ScalaClass(").append("Hello").append(")").toString();
 }
 
 public void printAllCharacters() {
 StringOps$.MODULE$.foreach$extension(Predef$.MODULE$.augmentString("Hello"), (Function1)(x -> Predef$.MODULE$.println(x)));
 }
}

&

import java.lang.invoke.SerializedLambda;
import scala.Function1;
import scala.Predef$;
import scala.collection.StringOps$;
public final class ScalaClass1
{
 private String in;
 
 public ScalaClass1(final String in) {
 this.in = in;
 }
 
 private String in() {
 return this.in;
 }
 
 private void in_$eq(final String x0ドル) {
 this.in = x0ドル;
 }
 
 public String getIn() {
 return this.in();
 }
 
 public void setIn(final String in1) {
 this.in_$eq("Hello");
 }
 
 public void printAllCharacters() {
 StringOps$.MODULE$.foreach$extension(Predef$.MODULE$.augmentString(this.in()), (Function1)(x -> Predef$.MODULE$.println(x)));
 }
 
 @Override
 public String toString() {
 return new StringBuilder(13).append("ScalaClass1(").append(this.in()).append(")").toString();
 }
}
You must be logged in to vote
0 replies
Comment options

What would happen if instead of using constants like:

public void setIn(final String in1) {
 this.in_$eq("Hello");
}

we use the variable instead

public void setIn(final String in1) {
 this.in_$eq(in1);
}

or produce runtime exception/compile time exception when compiling java/scala code combinedly.

You must be logged in to vote
0 replies
Comment options

A Scalafix rule could lint features not supported in Java or known interop issues.

At a glance, I don't see that such a rule has been written at https://scalacenter.github.io/scalafix/docs/rules/community-rules.html

You must be logged in to vote
1 reply
Comment options

This fix rule in indeed required to reduce programmer error.

Thank you

Answer selected by divyanshu-labs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /