We know how many inputs and outputs each operation has before we run the pipeline (although we need to compute this for an Array). Should we add checks that the given pipeline won't try to read from an empty stack, that each input is used, and that all outputs have a corresponding output path?
Even if we don't add the check, we could add num_outputs to the ImageOp trait instead of returning it from the apply method.