Skip to content

Different behavior of val and final val in objects #18698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
JD557 opened this issue Oct 15, 2023 · 2 comments
Closed

Different behavior of val and final val in objects #18698

JD557 opened this issue Oct 15, 2023 · 2 comments

Comments

@JD557
Copy link
Contributor

JD557 commented Oct 15, 2023

Compiler version

3.3.1

Minimized code

object Normal:
  val x = 5

object Final:
  final val x = 5

Output

public final class finalval$_$Normal$ implements java.io.Serializable {
  private final int x;

  public finalval$_$Normal$();
    Code:
       0: aload_0
       1: invokespecial #16                 // Method java/lang/Object."<init>":()V
       4: aload_0
       5: iconst_5
       6: putfield      #18                 // Field x:I
       9: return

  public int x();
    Code:
       0: aload_0
       1: getfield      #18                 // Field x:I
       4: ireturn
}

public final class finalval$_$Final$ implements java.io.Serializable {
  public finalval$_$Final$();
    Code:
       0: aload_0
       1: invokespecial #14                 // Method java/lang/Object."<init>":()V
       4: return

  public final int x();
    Code:
       0: iconst_5
       1: ireturn
}

Expectation

Since the generated classes for objects are final, I would expect that all vals declared in an object would be treated as final as well (including in this case, using iconst).

See VirtusLab/scala-cli#2462 for an example where this difference lead to huge performance differences on Java 8 and 11.

Notes

Like #17519, I'm not sure if changing this would trigger MiMA warnings, but since the class is already final I don't think there's any way for this to trigger binary compatibility problems.

I'm basing my expectations on this Stack Overflow question/answer: Non-final methods in a final class

@JD557 JD557 added itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Oct 15, 2023
@sjrd
Copy link
Member

sjrd commented Oct 15, 2023

That is by design.

Even in an object, you may not want to commit to the value staying the same forever. For a final val, you're committing to it, which allows the compiler to inline it. For a val, you still have the option to change its value in a subsequent release. Clients will then receive the new value without needing recompilation.

@sjrd sjrd closed this as not planned Won't fix, can't repro, duplicate, stale Oct 15, 2023
@sjrd sjrd added itype:invalid and removed itype:bug stat:needs triage Every issue needs to have an "area" and "itype" label labels Oct 15, 2023
@som-snytt
Copy link
Contributor

This is an ancient discussion, with scala 2 tickets about whether to emit the field or initialize it.

A quick search does not yield the classics, but here is one from "Baby Seth" (by analogy to "Baby Yoda"):
scala/bug#3142

There is also an old ticket somewhere about "final val is such a weak indicator, we should use explicit inline", so that I would hope for a fraught discussion about whether "final val" syntax could be retired someday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants