Skip to content

Backend ignores NoInits flag, always emit $init$ method on traits #2081

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
smarter opened this issue Mar 12, 2017 · 13 comments
Closed

Backend ignores NoInits flag, always emit $init$ method on traits #2081

smarter opened this issue Mar 12, 2017 · 13 comments

Comments

@smarter
Copy link
Member

smarter commented Mar 12, 2017

trait Foo {
  def meth(x: Int): Int
}

Compiled with dotty, then decompiled with cfr:

public interface Foo {
    default public void $init$() {
    }

    public int meth(int var1);
}

Compiled with Scala 2.12 then decompiled:

public interface Foo {
    public int meth(int var1);
}
@DarkDimius
Copy link
Contributor

This is not a backend issue, this is due to mixin.

@smarter
Copy link
Member Author

smarter commented Mar 12, 2017

Could you give some details?

@DarkDimius
Copy link
Contributor

@smarter, if you run the example you've posted with -Xprint:all, you'll see that $init$ method is created in
TreeTransform:{elimErasedValueType, vcElideAllocations, mixin, LazyVals, memoize, linkScala2ImplClasses, nonLocalReturns, capturedVars, constructors, functionalInterfaces, getClass}

Generally, in dotty the backend is very dumb. I've tried to move all logic away from it to parts of pipeline that are Y-checked.

@DarkDimius
Copy link
Contributor

DarkDimius commented Mar 12, 2017

I actually think that the current behavior is correct.
Otherwise adding a statement in a trait body would be binary incompatible.
Note that in Scala 2.12 you should also decompile implementation $class.

@smarter
Copy link
Member Author

smarter commented Mar 12, 2017

In both dotty and Scala 2.12 there are no implementation classes.

@DarkDimius
Copy link
Contributor

In both dotty and Scala 2.12 there are no implementation classes.

apparently for Scala 2.12 adding adding\removing statements in a trait body is binary incompatible.
I'd prefer to be more conservative in this case. Empty static method is very small and is optimizable away by VM, but it provides stronger binary compatibility guarantees.

@smarter
Copy link
Member Author

smarter commented Mar 12, 2017

@retronym Is the presence/absence of $init$ in traits and its effect on binary compatibility something that was considered during the development of 2.12?

@odersky
Copy link
Contributor

odersky commented Mar 13, 2017

@DarkDimius I don't think we should let our design decisions be influenced by binary compatibility at this stage. I still bet on Tasty to fix that.

@odersky odersky self-assigned this Mar 13, 2017
@DarkDimius
Copy link
Contributor

@odersky could we discuss this on the next dotty meeting?
The problem here is that it's not a compiler cross-version incompatibility that Tasty may fix.
It's real bytecode incompatibility as in NoSuchMethodException, unless the mainline compiler will be able to recompile classes in runtime.

@retronym
Copy link
Member

Related: scala/scala-dev#191

@retronym
Copy link
Member

I tend to think we should always emit the trait constructor unless the trait is marked with @FunctionalInterface or a similar annotation to restrict what features of traits are allowed (which in turn enables better interop with Java).

@retronym
Copy link
Member

retronym commented Mar 13, 2017

I've also considered indirecting calls to $init$ through an invokedynamic boostrap that turns into a no-op if that method no longer exists, ie, if the inherited trait changed from being a regular trait to a functional interface (without that method). This is of couse just a limited version of what a more general binary compatibilty repair tool could do.

@DarkDimius
Copy link
Contributor

I've also considered indirecting calls to $init$ through an invokedynamic boostrap that turns into a no-op if that method no longer exists, ie, if the inherited trait changed from being a regular trait to a functional interface (without that method). This is of couse just a limited version of what a more general binary compatibilty repair tool could do.

Could you please elaborate why this is better than a call to an empty static method?

smarter added a commit that referenced this issue Dec 31, 2017
Fix #2081: Don't issue an $init$ method for NoInits traits
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

4 participants