Skip to content
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

Removing method while making trait package-private is NOK #699

Conversation

armanbilge
Copy link
Contributor

Even though the trait is package-private in the current version, bincompat should still be enforced against the public version of the trait in the prior version.

This PR adds a failing test to demonstrate the issue. Not sure if I have the chops to fix it, but I'll give it a shot.

@armanbilge
Copy link
Contributor Author

Fixed my test, but broke two existing ones:

Failures:
* package-private-class-becomes-ok
* package-private-class-unbecomes-ok

package-private-class-becomes-ok seems to be asserting the exact opposite of what I'm asserting here. Library authors often make public things package private to make source-breaking changes while still retaining binary-compatibility. If something was public API in a previous version I would expect MiMa to enforce binary-compatibility for it going forward, even if it's no longer public API.

package-private-class-unbecomes-ok I need to take a closer look at.

@armanbilge
Copy link
Contributor Author

IIUC package-private-class-unbecomes-ok is looking at forward compatibility.

IMHO it should also be raising an error. According to scalacenter/sbt-version-policy#71 forward compatibility is used as a proxy for checking source-compatibility. Making a class public is not a source-compatible change.

@SethTisue
Copy link
Collaborator

First I'll just address the point about source compat.

It's not really MiMa’s business, as I understand it, to test anything except binary compatibility proper. I'm aware that sbt-version-policy chooses to use forward-and-backward bincompat as a "proxy" for source compatibility — an approximation, a stand-in, however you want to to describe it. But the fact that it’s doing so isn’t really, in my view, something you can bring back to this repo as the basis for a decision.

The readme here states:

MiMa focuses on binary compatibility and currently provides no insight into source compatibility

arguably that’s too unequivocal, and some such wording as “provides only incomplete insight” would be better, but regardless, my point stands.

@armanbilge
Copy link
Contributor Author

It's not really MiMa’s business, as I understand it, to test anything except binary compatibility proper.

I see your point, but I think it's a little blurry. If we were testing only binary-compatibility and nothing more, then MiMa shouldn't automatically filter any binary-incompatible changes, even those to package-private stuff, because package-private is a source-level concept.

Currently MiMa does have some understanding of whether changes are source-breaking or not and uses that to determine what to report.

For example, MiMa will not report a change to a package-private method, because even though it is binary-breaking, it is not source-breaking (because it's not public).

@SethTisue
Copy link
Collaborator

SethTisue commented Aug 2, 2022

As you were writing the above, I was writing the following:

That said, this business about package-private does seem to rather blur the line, doesn't it?

I'm not sure what the best way to think or talk about it this is. Perhaps you noticed that I never came back to scalacenter/sbt-version-policy#71 with any resolution of the ambivalence I expressed there. It isn't because I forgot, it's because even after all this time, I still don't know what I think.

I don't mean to rule out any invocation of any concept of source compatibility here in this repo, I'm only specifically casting shade on leaning on the "source compat (approximately) equals forward-and-backward-bincompat" equation/analogy/whatever-it-is.

In practice, MiMa users have a real and justifiable need to let pass some API changes which are technically not binary compatible at the bytecode level. This package-private business is an example of that.

I need to give the specific test cases you mention some further thought.

@SethTisue
Copy link
Collaborator

SethTisue commented Aug 2, 2022

One thing I'd like to ask @dwijnand here is: how do we currently think about forward compatibility in this repo? Historically, MiMa hasn't had a separate concept of forward compatibility. The exact same code was used to check both directions, and the forward-compat check consisted of simply swapping the order of the inputs.

Is that still the case, or did MiMa acquire a subtler notion of direction since I last looked? Was this considered at the time the package-private exemption was added?

@SethTisue
Copy link
Collaborator

SethTisue commented Aug 3, 2022

That question bears on whether it's valid to make arguments like:

IIUC package-private-class-unbecomes-ok is looking at forward compatibility

That seems hand-wavy and questionable to me. If I understand correctly, that test case was written and intended as a test of backward compatibility. Because the change is, in fact, backward compatible, yes?

MiMa is fundamentally a backward-compatibility checker and I think we need to tread very carefully as soon as we start talking about either “forward compatibility”, or “source compatibility".

wdyt?

@SethTisue
Copy link
Collaborator

Maybe @sjrd would like to bat these issues around along with us :-)

@armanbilge
Copy link
Contributor Author

That seems hand-wavy and questionable to me. If I understand correctly, that test case was written and intended as a test of backward compatibility.

I don't know. I'm just going by the fact that the test is making an assertion in the forwards direction, not the backwards :)

https://github.com/lightbend/mima/blob/c12aa686fe3b66c3896d850acbb2ae525d30714a/functional-tests/src/test/package-private-class-unbecomes-ok/forwards.txt

@SethTisue
Copy link
Collaborator

SethTisue commented Aug 3, 2022

I'm just going by the fact that the test is making an assertion in the forwards direction, not the backwards :)

Yeah. It looks like Dale added the forwards.txt thing in #542 in late 2020, and my concept of directionality in MiMa was already largely formed before then, so that's why I'm hoping Dale can fill us on on what the current concept is.

The readme is silent on the subject.

@SethTisue
Copy link
Collaborator

SethTisue commented Aug 3, 2022

my concept of directionality in MiMa was already largely formed before then

heh, but #87 (which was revised and merged as #104) dates all the way back to 2015, so I'm even behinder the times than I thought :-)

@dwijnand
Copy link
Collaborator

dwijnand commented Aug 3, 2022

package-private-class-becomes-ok seems to be asserting the exact opposite of what I'm asserting here. Library authors often make public things package private to make source-breaking changes while still retaining binary-compatibility. If something was public API in a previous version I would expect MiMa to enforce binary-compatibility for it going forward, even if it's no longer public API.

You're right and that test is wrong. I think I just wrote both directions and didn't think properly about it: the old API should be the reference point (thinking in terms of backwards binary compatibility being the main target use case for MiMa). I can look to making the suite pass as a whole.

I see your point, but I think it's a little blurry. If we were testing only binary-compatibility and nothing more, then MiMa shouldn't automatically filter any binary-incompatible changes, even those to package-private stuff, because package-private is a source-level concept.

Currently MiMa does have some understanding of whether changes are source-breaking or not and uses that to determine what to report.

For example, MiMa will not report a change to a package-private method, because even though it is binary-breaking, it is not source-breaking (because it's not public).

The idea was not coming at it from a "source-breaking" perspective but as a qualifier for what the public API is. For instance we always filtered out bytecode private methods, even if they changed, because no client code would suffer that change. We took that concept and extended it to the reality of package private access and annotated APIs, even if they're not enforced by the runtime, as a pragmatic convenience. Not because of any source compatibility concerns or desires.

One thing I'd like to ask @dwijnand here is: how do we currently think about forward compatibility in this repo? Historically, MiMa hasn't had a separate concept of forward compatibility. The exact same code was used to check both directions, and the forward-compat check consisted of simply swapping the order of the inputs.

Is that still the case, or did MiMa acquire a subtler notion of direction since I last looked? Was this considered at the time the package-private exemption was added?

Still the same: swap the order, compare the other way.

That seems hand-wavy and questionable to me. If I understand correctly, that test case was written and intended as a test of backward compatibility.

I don't know. I'm just going by the fact that the test is making an assertion in the forwards direction, not the backwards :)

c12aa68/functional-tests/src/test/package-private-class-unbecomes-ok/forwards.txt

That's would be to get the test to pass, with the various invariants the setup makes them hold (e.g. if you say there's a backwards problem, then running an app compiled against v2 running against v1 should blow up - fail the test if that's not true). Using a "fowards.txt" there is misleading, I agree - and there's probably already a way to make it work in a different way, with the various "pending"/etc escape hatches that are set up.

Reclassify package-private-class-becomes as breaking, my bad.

Fix package-private-class-unbecomes, and the fix also correct the
confusion: it's a backwards binary compatibility test.
Write the test in Scala seeing though we can, and it's hard to write it in Java such that it cross-compiles in Scala 2.11-3
@sjrd
Copy link
Contributor

sjrd commented Aug 3, 2022

The idea was not coming at it from a "source-breaking" perspective but as a qualifier for what the public API is. For instance we always filtered out bytecode private methods, even if they changed, because no client code would suffer that change. We took that concept and extended it to the reality of package private access and annotated APIs, even if they're not enforced by the runtime, as a pragmatic convenience. Not because of any source compatibility concerns or desires.

On mobile (and on vacation this week), so I'll limit my comment to saying that I fully agree with that quoted comment. ;)

@dwijnand dwijnand merged commit 295754c into lightbend-labs:main Aug 3, 2022
@SethTisue
Copy link
Collaborator

You're right and that test is wrong

ah okay good well that's simple then :-)

@SethTisue SethTisue added this to the 1.1.1 milestone Sep 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants