-
Notifications
You must be signed in to change notification settings - Fork 6
Enable Optional Parameters Using Reduction #32
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
Conversation
These methods tell us about the presence of Optional parameters on the Op
We want to leave open the possibility for @optional annotations to be declared on the interface as well as on the Op implementation. This means we have to check multiple Methods for the Optional annotation. This could be a source of bugs, but for now we check any method with the same name as the functional method, having the same number of parameters.
63fa3a2 to
c075c6f
Compare
Field reductions will be very rare, since you cannot annotate lambda parameters, but it is not too difficult to add support for Field Ops that are anonymous classes
This was really confusing, now it is less so :)
In writing this test I found that getMethods works differntly than I expected. I knew that there were two instances of the functional method that were being returned by Class.getMethods(). I did not realize that both were from the class (I had thought that one came from the implemented functional interface). It turns out that both come from the class, so we need to do some extra introspection on the functional interface
Unfortuantely, this results in some API changes in OpEnvironment.
Reduces duplicated code
This makes it easier to parallelize later
Not only IS it a functional interface, but our findFunctionalInterface logic will delegate to Supplier otherwise (which is bad)
We need the names to correctly implement the interfaces/call the original method
These tests show that reduction with dependencies works regardless of where the Dependencies are in the signature, which is uber cool!
This check was never necessary
c075c6f to
7d1d7d4
Compare
|
What about default parameters in Kotlin? |
How does that help us, unless we convert our entire codebase to Kotlin? Tangentially, I suppose that, if one wrote an Op in Kotlin, we could have a |
This commit ports the work from #32, updating it to the latest schemes of discovery. Please see that PR for a summary of how reduction operates
|
Closing in favor of #58. |
This PR introduces the ability to declare optional parameters in an Op's functional method using the
@Optionalannotation. The motivation behind this implementation was to maintain from ImageJ Ops the ability to declare optional parameters without the complexity of field injection.Once one parameter (or more) has been declared optional for some Op, scijava ops will create a set of
ReducedOpInfos for that Op; if an Op hasnoptional parameters, we will then haven+1OpInfos that delegate to that Op (nof which beingReducedOpInfos). TheseReducedOpInfos can then be matched, just as any otherOpInfo. We maintain ImageJ Ops' behavior of matching subsets of optional parameters in a left-to-right manner; this means that if there is anOpMethodwe can match this Op using:
aaandba,b, andc.We do not allow the matching of
aandc, as whenbandcare the same type, passing aDoublewould provide no indication whether thatDoubleshould be assigned toborc. To be deterministic we assume that optional parameters are always left off right to left.Using this paradigm, users can write a class Op with optional parameters as
When this Op is called without the optional parameter, the
ReducedOpInfowill use Javassist to create a wrapper forOptionalArgClass, passingnullfor each optional parameter that is omitted in the matchedReducedOpInfo. note that the Op author is then responsible for null-checking any optional arguments.Using the
OpBuildersyntax, this Op can then be called using eitheror
Ops written as methods can similarly be written with optional parameters:
When writing an Op as a
Field, there are two options. One can write the Op as either an anonymousClass:or, with the help of a specialized interface, using a lambda:
To promote extensibility, each
OpInfois reduced using aInfoReducerplugin.InfoReducers are designed to be able to reduceOpInfos backed by one of a set of functional types (for example, aFunctionReducershould reduce allFunctions). For each functional type anInfoReducercan reduce, it should be able to produce anOpInfofor any number of optional parameters. So if, for example, anInfoReduceris able to reduce aFunctions.Arity3, it should be able to reduce thatArity3into aBiFunction, aFunction, and aProducer.OpInforeduction is performed at plugin discovery time, and the Javassist wrapper is created when the Op is matched.Closes scijava/scijava#14