-
Notifications
You must be signed in to change notification settings - Fork 54
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
Reconsider (remove?) ApiXmlAdjuster #587
Comments
After a night's sleep, there's a problem with the "let's just use Consider this Java code: class MyExampleAdapter extends LeanbackListPreferenceDialogFragment.AdapterMulti {
@Override
public void onBindViewHolder(LeanbackListPreferenceDialogFragment.ViewHolder holder, int position) {
/* ... */
super.onBindViewHolder(holder, position);
}
} The compiler emits overrides for both the synthetic and non-synthetic methods, a'la class MyExampleAdapter extends LeanbackListPreferenceDialogFragment.AdapterMulti {
@Override
public void onBindViewHolder(LeanbackListPreferenceDialogFragment.ViewHolder holder, int position) {
/* ... */
super.onBindViewHolder(holder, position);
}
// compiler-emitted synthetic method
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
/* ... */
super.onBindViewHolder(holder, position);
}
} but if we rely exclusively on the Synthetic method -- "skipping" the class MyExampleAdapter extends LeanbackListPreferenceDialogFragment.AdapterMulti {
// If we try to manually write method with a "synthetic method"-compatible signature...
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
/* ... */
super.onBindViewHolder(holder, position);
// error: incompatible types: RecyclerView.ViewHolder cannot be converted to LeanbackListPreferenceDialogFragment.ViewHolder
}
} Thus, removing the synthetic method -- as |
The above explanation actually brings to light the problem with altering the [Register ("onBindViewHolder", "(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V", "GetOnBindViewHolder_Landroidx_recyclerview_widget_RecyclerView_ViewHolder_IHandler")]
public override unsafe void OnBindViewHolder (global::AndroidX.RecyclerView.Widget.RecyclerView.ViewHolder holder, int position)
{
const string __id = "onBindViewHolder.(Landroidx/recyclerview/widget/RecyclerView$ViewHolder;I)V";
try {
JniArgumentValue* __args = stackalloc JniArgumentValue [2];
__args [0] = new JniArgumentValue ((holder == null) ? IntPtr.Zero : ((global::Java.Lang.Object) holder).Handle);
__args [1] = new JniArgumentValue (position);
_members.InstanceMethods.InvokeVirtualVoidMethod (__id, this, __args);
} finally {
}
} This "works", to the extent that the binding compiles, and to the extent that you can call the var instance = ...
instance.OnBindViewHolder (holder, position); But you cannot override public class MyFragment : LeanbackListPreferenceDialogFragment {
public class MyAdapter : LeanbackListPreferenceDialogFragment.AdapterMulti {
public override void OnBindViewHolder (global::AndroidX.RecyclerView.Widget.RecyclerView.ViewHolder holder, int position)
{
base.OnBindViewHolder (holder, position);
}
}
} Because the |
My minimal example code for exploring synthetic methods: package synthetic_example;
interface Fooable<T extends Runnable> {
void foo(T value);
}
class MyRunnable implements Runnable {
public void run() {
}
}
class MyRunnableFooable implements Fooable<MyRunnable> {
public void foo(MyRunnable value) {
}
}
class MyExtendedRunnableFooable extends MyRunnableFooable {
@Override
public void foo(MyRunnable value) {
}
/* trying to explicitly use the following method fails to compile
@Override
public void foo(Runnable value) {
super.foo(value);
}
*/
} |
We may want to remove |
Background: In The Beginning, Google provided an API XML file, and we used that as input to
generator
to produceMono.Android.dll
. It Was Good...except we couldn't bind anything else. Then API-H/Honeycomb came out and didn't have an API XML file, so we createdjar2xml
to create an API XML description which we could continue feeding togenerator
, and It Was Good....well, mostly.
jar2xml
had problems if any types were unresolvable, which wasn't that uncommon in practice, soclass-parse
was written to create an API XML description......which couldn't be fed to
generator
.class-parse
emitted the same XML dialect asjar2xml
(which was similar to the original Google dialect), as it read data based on what was in.class
files, which differs from what Java reflection "sees", it was sufficiently different that trying to useclass-parse
xml withgenerator
would result in Pain and Suffering. (@dellis1972 likely remembers some of that...)The fix was
Xamarin.Android.Tools.ApiXmlAdjuster
, which would readclass-parse
XML and mutate it to be "more like"jar2xml
XML, which could then be fed intogenerator
for bindings:https://github.com/xamarin/xamarin-android/blob/2722719279df2665e82ff772f14b779c551bb2ea/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Bindings.targets#L394-L411
The Problem: We want
generator
to be Robust and Bug Free™ (arguably impossible, but go with it!), so enter Issue #586 and #586 (comment)One of the problems in Issue #586 is that
generator
doesn't takemanagedType
overrides into consideration when determining whether a method should be anoverride
or not.The real problem, though, is that any fixup was required at all. The "current fix" in #586 is to change
//@type
(?!) so that the resulting C# code compiles, while arguablymanagedType
should be usable, but isn't.BUT NO CHANGES SHOULD BE REQUIRED AT ALL.
Why are any changes needed to bind
androidx.leanback
?The Solution (?):
One of the members that ApiXmlAdjuster removes are "synthetic" methods, which are methods emitted by the compiler and not written by the developer. This makes sense as they're compiler-generated, yet...
In the case of Issue #586, the synthetic method matches C# requirements! Because of type erasure,
RecylerView.Adapter<VH>.onBindViewHolder(VH, int)
is reallyRecylerView.Adapter.onBindViewHolder(RecyclerView.ViewHolder, int)
, which Turns Out™ to be exactly what C# needs for override resolution purposes!Thus: can we remove ApiXmlAdjuster, and use the original data within
class-parse
to emit more reliable bindings? Could we rely on synthetic methods as part of our binding strategy, as those may be closer to C# API semantics than what we're currently trying to do?The text was updated successfully, but these errors were encountered: