Skip to content
Alessandro Felder edited this page Apr 10, 2019 · 9 revisions

How are the ops named?

Each op has a name, which is not necessarily unique. This allows multiple "overloaded" ops with different combinations of parameter types, similar to the method overloading feature of Java and other programming languages.

Ops may optionally have a namespace. This is similar to packages in Java and similar features in other languages. The namespace is expressed as a prefix; such ops are referenced by their namespace, followed by a dot, followed by the op name. Ops without a namespace belong to the "global" namespace, with no prefix or dot. Two ops with the same name but different namespaces do not "overload" or "override" one other.

The naming convention for both namespaces and op names is to use an alphameric string, in lower camel case.

How are the Java classes and packages named?

We use the following guidelines:

  • Each kind of operation has an associated interface in the net.imagej.ops.Ops container class, nested beneath its namespace. For example, ops named math.add implement the Ops.Math.Add interface. The Ops container class is autogenerated from a Velocity template; see Ops.list and Ops.vm.
  • Each kind of operation lives in an associated package matching its namespace and op name. For example, ops named math.add are declared in the net.imagej.ops.math.add package.
  • It is OK to have subinterfaces for different sorts of ops with the same name, if needed.
  • For each Ops.Foo.Bar interface:
    • Optionally create a net.imagej.ops.foo.BarOp interface which extends it. Typical reasons for having this additional interface include: to compose with other interfaces, to add generic parameters, and/or to add needed API methods. The reason for the Op suffix is to avoid naming confusion—especially if the operations work with a data structure of the same name. E.g., a MeanOp might compute a Mean, a SmallestEnclosingRectangleOp might compute a SmallestEnclosingRectangle, and so on.
    • Optionally, create a net.imagej.ops.foo.AbstractBar base class.
    • Create one or more concrete implementing subclasses, each annotated with @Plugin. Name your concrete implementing classes in a way that will differentiate them, typically by referencing their input type arguments somehow—e.g., CorrelateFFTImg and CorrelateFFTRAI. If you have a single concrete implementing class, it will typically be named net.imagej.ops.foo.DefaultBar. See the type hierarchy of net.imagej.ops.identity for a simple example.

How are the built-in method signatures structured?

The OpService provides built-in type-safe methods corresponding to all ops available in the core Ops library. These methods are consistent with the patterns discussed above: global ops have methods directly in OpService, while the ops of a particular namespace are accessible via their Namespace class, which is accessible from the OpService. For example, to call a math.add op, you would write ops.math().add(...), where ops is a reference to the OpService instance.