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

Structural Interfaces: support structural interfaces dynamically without having manifold-ext dependency at runtime #240

Closed
rsmckinney opened this issue Jan 26, 2021 · 0 comments
Labels
enhancement Extensions Relates to the ExtensionManifold

Comments

@rsmckinney
Copy link
Member

rsmckinney commented Jan 26, 2021

Basically, support structural interface calls without static proxies and without manifold dynamic compilation at runtime.

The problem, or gap, with the current situation is that by default structural interfaces require the manifold-ext dependency at runtime, which adds significant size and complexity to applications that otherwise isn't necessary with other manifold features -- most feature resolve exclusively at compile-time via the Manifold Javac plugin with no further code generation required at runtime.

Currently, one can write static proxies via "implementation by proxy" to avoid the manifold-ext runtime dependency, however writing these can be prohibitive, particularly with high volume and/or high complexity of proxies.

Here we propose an alternative approach, which is to generate the proxies at runtime using the standard Java Proxy service. The meat of this proposal is to provide structural invocation support from ReflectUtil, which amounts to implementing a method such as:

public static Object structuralCall( Method structuralMethod, Object receiver, Object... args ) { . . . }

There are two primary challenges involved in implementing such a method.

  1. Structural call-compatibility
  2. Method overloading

Structural call-compatibility is about method signature variance. Essentially, if a receiving method's parameters are contravariant and the return type is covariant with the call-site method, they are structurally call-compatible. See Type assignability and variance.

Method overloading supports a type with multiple methods having the same name varying by parameter types.

Thus, the challenge is to build a "best method" resolver that, given a structural interface method signature, chooses the most suitable, structurally call-compatible method on the receiver type. This resolver amounts to defining and implementing a method scoring algorithm similar to the one the Java compiler uses.

Once we have the "best method" resolver in hand, the rest is a simple matter of using it to implement the new structuralCall methods in ReflectUtil such as the one outlined earlier. In turn these methods will be leveraged with Java's Proxy service to build dynamic proxies in RuntimeMethods#createProxy when manifold-ext is not used at runtime.

Upside: Eliminates the manifold-ext dependency when using structural interfaces.
Downside: Reduced performance per structural call since manifold-ext-generated proxies make direct InvokeVirtual calls while this approach makes indirect calls using reflection.
Conclusion: Having this feature will allow projects to quickly begin using structural typing without having Manifold and Javac compilation services complicate and bloat their runtime. If performance becomes an issue, projects can apply "implementation by proxy" where needed for maximum performance and still avoid the dependency.

@rsmckinney rsmckinney added enhancement Extensions Relates to the ExtensionManifold labels Jan 26, 2021
rsmckinney added a commit that referenced this issue Jan 29, 2021
- support structural interfaces dynamically without having `manifold-ext` dependency at runtime
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Extensions Relates to the ExtensionManifold
Projects
None yet
Development

No branches or pull requests

1 participant