-
Notifications
You must be signed in to change notification settings - Fork 533
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
[Mono.Android] Bind Android 15 DP 2 #8741
Conversation
df946c1
to
540bd4b
Compare
5016506
to
c7ac17a
Compare
43d2b83
to
d56e439
Compare
Context: #8741 Create a copy of the API-34 `PublicAPI.*` comparison files for API-35. Doing this before we commit API-35 ensures that we will have a "shipped" baseline to compare against, so that any potential changes caused by API-35 will be surfaced in the PR diff. Note these files are not consumed yet. They will be consumed when API-35 is committed.
src/Mono.Android/Java.Util/IList.cs
Outdated
#if ANDROID_35 | ||
public partial interface IList | ||
{ | ||
// This gets generated as: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this comment. Do you mean the body of n_Reversed()
? If so, should the comment be moved there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved.
|
||
<!-- API-35 adds new java.util.Sequenced[Collection|Map] interfaces that existing interfaces/classes now implement. --> | ||
<!-- Fix covariant return types for new 'reversed ()' method. --> | ||
<attr api-since="35" path="/api/package[@name='java.util']/interface[@name='List']/method[@name='reversed' and count(parameter)=0]" name="managedReturn">Java.Util.ISequencedCollection</attr> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like we'll wind up having two Reversed
methods in the inheritance tree, a'la:
interface ISequencedCollection {
ISequencedCollection Reversed();
}
interface List : ISequencedCollection {
ISequencedCollection Reversed();
}
If correct, shouldn't we instead "reabstract" IList.Reversed()
? dotnet/java-interop@22d5687
…and ditto most of the subsequent managedReturn
changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is how it looks in Java:
public interface SequencedCollection<E> extends Collection<E> {
SequencedCollection<E> reversed();
}
public interface List<E> extends SequencedCollection<E>, Collection<E> {
default List<E> reversed() {
throw new RuntimeException("Stub!");
}
}
This is just a normal "provide a default
implementation for an inherited interface method".
I think reabstraction is for the opposite case: when we want to "hide" a default
implementation and make it abstract
again.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Aside: This is a matter of "leaky abstraction I'd rather not make worse". C# permits "explicitly implementing interfaces", which is required for things like IEnumerable.GetEnumerator()
vs. Enumerable<T>.GetEnumeartor()
(same name! Different semantics! Supported via explicitly implementing interface members).
Java does not have an equivalent to explicit interface implementation. All method names must have the same semantics and "compatible" return types.
This is a "leaky abstraction" that we've long allowed to happen, largely because we had no way to address it other than <remove-node/>
(which perhaps we should have done?), which results in things like:
namespace Java.Util;
partial interface ICollection {
bool IsEmpty {get;}
bool Add (Object? e);
// …
}
partial interface IList : ICollection {
// same methods
bool IsEmpty {get;}
bool Add (Object? e);
}
Things are "fine" so long as you don't explicitly implement them. If you do:
class MyList : Java.Lang.Object, Java.Util.IList {
bool Java.Util.ICollection.IsEmpty { get => true; }
bool Java.Util.IList.IsEmpty { get => false; }
}
which do you get? There Can Be Only One™.
Answer: IList.IsEmpty
, because it's the most derived type, as per the JCW:
__md_methods =
"n_isEmpty:()Z:GetIsEmptyHandler:Java.Util.IListInvoker, Mono.Android, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null\n" +
So it "works", but is not necessarily ideal.
Thus, the question: What is ideal, and can we get closer to it?
Given that our current C# approach results in numerous C# warnings that we have to ignore (CS0114), I think that the ideal scenerio would be to "reabstract" the members:
namespace Java.Util;
interface IList : ICollection {
abstract bool ICollection.Add(Java.Lang.Object? e);
abstract bool ICollection.IsEmpty {get;}
}
This would allow you to explicitly implement e.g. only ICollection.Add()
, and not IList.Add()
, as they're now "flattened"/"unified".
We can't do this for existing members (API & ABI break).
We can do this for newly added members, if/when appropriate.
On to default
method implementations: C# supports this as well, again via explicit interface implementation:
namespace Java.Util;
interface ICollection {
// has a body for back-combat reasons
ISequencedCollection Reversed() => throw new NotImplementedException();
}
interface IList : ICollection {
IList ICollection.Reversed() => _members.InstanceMethods.InvokeAbstracMethod(…);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm not sure if your latest comment is suggesting a change? or just opining? 😁
Er, yes.
Background info, plus opinion on where we should consider going, neither of which is directly relevant for .Reversed()
. The comment is thus not actionable.
My bad.
However, now that I have that background thinking in place, it allows me to point to:
SequencedCollection
and/vsList
Both declare getFirst()
/getLast()
/removeFirst()
/removeLast()
/reversed()
methods, suggesting -- as I haven't build this PR locally, I just believe that this will likely be the case -- that the binding with this PR as-is will contain:
namespace Java.Util;
partial interface ISequencedCollection {
void AddFirst(Object? e);
void AddLast(Object? e);
Object? GetFirst();
Object? GetLast();
// …
}
partial interface IList : ISequencedCollection {
void AddFirst(Object? e); // CS0114 warning
void AddLast(Object? e); // CS0114 warning
Object? GetFirst(); // CS0114 warning
Object? GetLast(); // CS0114 warning
// …
}
and I ask: should it be this way?
It's been this way, so it's not "broken" per-se, but it doesn't feel "entirely proper" either.
There are two solutions for making this "more proper":
- Use
<remove-node/>
to remove the of identically declared methods fromList
. - Use
reabstract
metadata to declare theIList
methods asabstract
and explicltly declare them.
Or (3), update generator
to internally handle (1) or (2). :-).
Which becomes all the more important/required given that we don't know how many other interfaces this impacts (though SequencedMap
/Map
& SequencedSet
/Set
also hit it, minimum). (For comparison, if I stop ignoring CS0114 in Java.Base
, there are 61 warnings emitted that I now feel shouldn't be emitted, and that's a very small subset of java.base.jmod
…)
This comment is thus deeply in "the perfect is the enemy of the good" territory, mind you…
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
…so where does that leave me?
If we were doing it all over again -- cough Java.Base
cough -- then I'd want the CS0114 warnings to not be emitted by tooling, either by removing identically declared overriding members or by re-abstracting them.
However, we're not doing it all over again, we have no tooling to assist in finding these situations (other than re-enabling CS0114, which would introduce 686 warnings!), so manually fixing these is a non-starter. We could update generator
, but I'm not certain that we have the time, and this would need to be an "opt-in" construct, somehow, so that we don't re-abstract or remove previously declared methods (though API-compat is a good backstop for this).
I thus think that we can't/shouldn't attempt to address this right now. :-(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attempted to clarify my thinking here: dotnet/java-interop#1215
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think my sticking point with understanding this is that the new methods defined in IList
are default
methods, so I'm not sure that I comprehend marking them abstract
with reabstraction.
IE:
namespace Java.Util;
partial interface ISequencedCollection {
void AddFirst(Object? e);
void AddLast(Object? e);
Object? GetFirst();
Object? GetLast();
// …
}
partial interface IList : ISequencedCollection {
void AddFirst(Object? e) { // implementation }; // CS0108 warning
void AddLast(Object? e); { // implementation }; // CS0108 warning
Object? GetFirst(); { // implementation }; // CS0108 warning
Object? GetLast(); { // implementation }; // CS0108 warning
// …
}
Aside, it's a CS0108
warning instead of CS0114
.
CS0108 'IList.AddFirst(Object?)' hides inherited member 'ISequencedCollection.AddFirst(Object?)'. Use the new keyword if hiding was intended.
I think CS0108
is the point you are getting at: we aren't "providing an default implementation of ISequencedCollection.AddFirst
", we are declaring a new AddFirst
that hides the original one.
However we appear to actually handle this correctly for the specific case where a DIM is providing an implementation for an inherited interface method, as this is what we generate:
partial interface IList : ISequencedCollection {
void Java.Util.AddFirst(Object? e) { // implementation };
void Java.Util.AddLast(Object? e); { // implementation };
Object? Java.Util.GetFirst(); { // implementation };
Object? Java.Util.GetLast(); { // implementation };
// …
}
This prevents the CS0108
warning and provides the correct "provide a default implementation" semantics rather than hiding the inherited method.
Looking at other existing methods in IList
/ICollection
I do see what you are talking about:
public partial interface ICollection
bool AddAll (System.Collections.ICollection c);
}
public partial interface IList : Java.Util.ICollection {
bool AddAll (System.Collections.ICollection c); // CS0108
}
Fixing that (which we do not do today) indeed would be:
abstract bool ICollection.AddAll (System.Collections.ICollection c);
To your point, without a way to detect these cases currently, we do not know if API-35 adds any additional cases that we could manually fix with reabstraction or removal.
<attr api-since="35" path="/api/package[@name='java.util']/class[@name='LinkedList']/method[@name='reversed' and count(parameter)=0]" name="managedReturn">Java.Util.ISequencedCollection</attr> | ||
|
||
<!-- Removed because it simply narrows the method return type, which we cannot change anyways. (SequencedCollection -> SequencedSet) --> | ||
<remove-node api-since="35" path="/api/package[@name='java.util']/interface[@name='SequencedSet']/method[@name='reversed' and count(parameter)=0]" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be another case for "reabstraction". Though ABI-wise, i think removing this method should also work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In Java, this is:
public interface SequencedCollection<E> extends Collection<E> {
SequencedCollection<E> reversed();
}
public interface SequencedSet<E> extends SequencedCollection<E>, Set<E> {
SequencedSet<E> reversed();
}
C# does not support covariant return type changes from implemented interfaces. We could fix the covariant return type, but then the methods are identical, so I just removed it instead.
* main: Bump to xamarin/xamarin-android-binutils/L_18.1.4-8.0.0@758d2e7 (#8885) [Mono.Android] Bind API-VanillaIceCream Beta 1 (#8891) [AndroidToolTask] Log tool output as error (#8861) [Xamarin.Android.Build.Tasks] Remove "Xamarin" from messages (#8884) [Mono.Android] Bind API-VanillaIceCream Developer Preview 2 (#8741) Bump to dotnet/installer@22ffa42d6c 9.0.100-preview.4.24221.5 (#8887) Bump external/xamarin-android-tools from `37d79c9` to `05f9a90` (#8869) Bump external/Java.Interop from `e1c7832` to `06214ff` (#8878) Bump to dotnet/installer@7380c301c1 9.0.100-preview.4.24215.2 (#8874) [Mono.Android] Commit baseline PublicAPI files for API-35 (#8840) Add a unit test to check environment processing (#8856) Don't use azureedge.net CDN (#8846) Bump to dotnet/installer@0bfd2dd757 9.0.100-preview.4.24208.2 (#8862) [ci] Update dependabot ignore list (#8864) Bump external/Java.Interop from `651de42` to `e1c7832` (#8836) Bumps LLVM to v18.1.3 and XA utils version to 8.0.0 (#8852)
* main: Bump to xamarin/xamarin-android-binutils/L_18.1.4-8.0.0@758d2e7 (#8885) [Mono.Android] Bind API-VanillaIceCream Beta 1 (#8891) [AndroidToolTask] Log tool output as error (#8861) [Xamarin.Android.Build.Tasks] Remove "Xamarin" from messages (#8884) [Mono.Android] Bind API-VanillaIceCream Developer Preview 2 (#8741) Bump to dotnet/installer@22ffa42d6c 9.0.100-preview.4.24221.5 (#8887)
* main: (26 commits) [Mono.Android] fix potential leak of RunnableImplementors (#8900) [build] Bump $(AndroidNetPreviousVersion) to 34.0.95 (#8898) [docs] Reorganize public Documentation (#8889) Bump external/Java.Interop from `06214ff` to `6cfa78c` (#8879) Localized file check-in by OneLocBuild Task (#8894) $(AndroidPackVersionSuffix)=preview.5; net9 is 34.99.0.preview.5 (#8896) Bump to xamarin/monodroid@a5742221b3 (#8893) Remove MonoArchive_BaseUri from Configurables.cs (#8890) Bump to xamarin/xamarin-android-binutils/L_18.1.4-8.0.0@758d2e7 (#8885) [Mono.Android] Bind API-VanillaIceCream Beta 1 (#8891) [AndroidToolTask] Log tool output as error (#8861) [Xamarin.Android.Build.Tasks] Remove "Xamarin" from messages (#8884) [Mono.Android] Bind API-VanillaIceCream Developer Preview 2 (#8741) Bump to dotnet/installer@22ffa42d6c 9.0.100-preview.4.24221.5 (#8887) Bump external/xamarin-android-tools from `37d79c9` to `05f9a90` (#8869) Bump external/Java.Interop from `e1c7832` to `06214ff` (#8878) Bump to dotnet/installer@7380c301c1 9.0.100-preview.4.24215.2 (#8874) [Mono.Android] Commit baseline PublicAPI files for API-35 (#8840) Add a unit test to check environment processing (#8856) Don't use azureedge.net CDN (#8846) ...
Context: https://developer.android.com/about/versions/15
Context: https://android-developers.googleblog.com/2024/03/the-second-developer-preview-of-android-15.html
Android 15 Developer Preview 2 has been released. The Android 15
Developer Preview Program Overview Timeline and updates section
suggests the following timeline:
This will be usable in its preview form to .NET 9 Preview users who explicitly target
net9.0-android35
.PublicApiAnalyzers
reports 3 categories of API changes (PublicAPI.Shipped.txt
):?
->!
)virtual
tooverride
due to implementation being provided by base class