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

Make IJavaPeerable implementable #17

Open
jonpryor opened this issue May 19, 2015 · 6 comments
Open

Make IJavaPeerable implementable #17

jonpryor opened this issue May 19, 2015 · 6 comments
Labels
enhancement Proposed change to current functionality java-interop Runtime bridge between .NET and Java

Comments

@jonpryor
Copy link
Member

https://twitter.com/sh4na/status/600662831017676800

If a user of your API complains of breakage and you reply “oh, you shouldn’t be doing that”, it’s a sign that your API is badly designed.

What's the problem with IJavaPeerable? It shouldn't be implemented by developers. Ever. (In theory it could be properly implemented. In practice, I wouldn't want to try to do so.)

We should nuke the IJavaPeerable interface from the public API.

Problem: JniPeerMethods and other types make use of IJavaObject, which would need to be fixed. Perhaps we could refactor things to remove the problematic members, e.g. IJavaPeerable.PeerReference?

@jonpryor jonpryor changed the title Make IJavaObject implementable Make IJavaPeerable implementable Oct 23, 2015
@jonpryor
Copy link
Member Author

A closely related problem is Xamarin.Android's tools/generator, which generates binding assemblies, which would be using Java.Interop.JniPeerMembers. JniPeerMembers.JniInstanceMethods, meanwhile, uses IJavaPeerable and IJavaPeerable.PeerReference extensively; how can it possibly work without an IJavaPeerable type?

The only way I can think of to make it work without an IJavaPeerable type is to instead emit overloads for e.g. JniPeerMembers.JniInstanceMethods.InvokeAbstractVoidMethod() which take both a JavaObject and a JavaException...which ~immediately breaks the current Xamarin.Android integration strategy because those types won't exist in the Cycle 7 Java.Interop.dll that Xamarin.Android 6.1 will be using.

So that's a bit of a non-starter.

@jonpryor
Copy link
Member Author

At present, I can't think of a way to satisfy the goal of having a sanely designed API (no interfaces that can't actually be implemented) which is also usable and fulfills known compatibility and integration points.

Keeping this open (for now) should a brain storm occur, but I don't see how it can happen.

@jonpryor
Copy link
Member Author

Related: https://bugzilla.xamarin.com/show_bug.cgi?id=37560

People see an interface, and try to manually implement, and shit breaks. Film at 11.

Even if the interface were implementable...they'd probably implement it wrong, because they're clearly already trying to implement the interface even when the documentation explicitly says not to.

@jpobst
Copy link
Contributor

jpobst commented Apr 16, 2020

Closing, as this seems unlikely at this point.

@jonpryor
Copy link
Member Author

jonpryor commented Mar 28, 2022

After discussion with @jpobst, we can probably:

  1. Provide default implementations for all members on IJavaPeerable, and
  2. Update jcw-gen to look for IJavaPeerable as an implemented interface, and generate Java Callable Wrappers when found.

These changes would allow this to compile and work as expected:

class MyRunnable : Java.Lang.IRunnable {
    public void Run() { /* … */ }
}

Doing this would require use of ConditionalWeakTable<TKey, TValue> to implement IJavaPeerable.PeerReference/etc., which might not be "ideal", but should be possible.

@jonpryor jonpryor reopened this Mar 28, 2022
@jonpryor
Copy link
Member Author

After some further thought…

Can we implement IJavaPeerable via ConditionalWeakTable<TKey, TValue>? Kinda. We can implement the C# side, in a way that works:

var list = new Java.Util.ArrayList ();
lits.Add (new MyRunnable());
var r = (MyRunnable) list.Get (0);

The problem is, this overlooks the GC bridge:

On Mono, the GC bridge currently requires that the type provide 4 fields (handle, handle_type, refs_added, weak_handle), and as an interface cannot provide instance fields, this is a problem:

var list = new Java.Util.ArrayList ();
lits.Add (new MyRunnable());

/* Do Something to cause the `MyRunnable` to be collected; GC.Collect(), etc. */

var r = (MyRunnable) list.Get (0);
// throws a `NotSupportedException` as there isn't an "activation constructor"
// for `MyRunnable`

This can be "solved" by not using the existing GC bridge, a'la https://github.com/jonpryor/Java.Interop/commits/jonp-registration-scope , or by otherwise rethinking how cross-VM object references work.

@jpobst jpobst added enhancement Proposed change to current functionality java-interop Runtime bridge between .NET and Java labels Feb 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Proposed change to current functionality java-interop Runtime bridge between .NET and Java
Projects
None yet
Development

No branches or pull requests

2 participants