Open ctrueden opened 6 months ago
@ctrueden thanks for raising this issue. I've thought about it a fair bit, and did a little prototyping to try and fix this issue, and I can't come up with a solution that I like - you get drawn into casting issues so easily. Here's what I've been thinking about:
public <T> T opFromSignature(final String signature, final Class<T> rawOpType)
This option is basically what you asked for above, but a little simpler without the Nil
. While this is very easy to implement, it starts to reintroduce output casting in a way we tried to avoid with SciJava Ops.
// some signature for a BiFunction<Img, double, Img>
var sig = ...
var img = ...
var sigma = 5.0;
var op = env.signature(sig, BiFunction.class); // This would return a raw BiFunction
// -- EITHER -- //
Img out1 = (Img) op.apply(img, sigma); // Requires cast
// -- OR -- //
var out2 = op.apply(img, sigma); // autocomplete only recognizes `Object` members on `out`.
Then, I figured that if we're going for simplicity, maybe we should just do this:
public Object opFromSignature(final String signature)
But, while this look slick in a scripting environment, it'd make the casting even worse in languages where it's needed:
// some signature for a BiFunction<Img, double, Img>
var sig = ...
var img = ...
var sigma = 5.0;
var op = (BiFunction<Img, double, Img>) env.signature(sig); // This would return an Object, cast required for following line
Img out1 = op.apply(img, sigma);
Since we worked so hard on the OpEnvironment
methods to remove these casts from the original ImageJ Ops code, it feels like a step back, no?
What I'd propose instead, if you really want this type of behavior, is a static function that could live...anywhere, really, although I'd prefer to put it closer to the scripts if possible (i.e. some future scijava-ops-python component down the line, that also contains the gateway?). It would look more or less like:
public static Object reconstruct(final OpEnvironment env, final String signature) {
InfoTree tree = env.treeFromSignature(signature);
Nil<?> type = Nil.of(tree.info().opType());
return env.opFromInfoTree(tree, type);
}
Then, in e.g. Python you could write:
sig = ...
img = ...
sigma = 5.0
out = Ops.reconstruct(env, sig).apply(img, sigma)