What if we were more relaxed about “matching signatures”

We care about input and output ports in several places.

1. Uncontroversially, I think, atomic steps declare their ports and
it’s a static error to attempt to write to a input port that doesn’t
exist or read from an output port that doesn’t exist. (There’s a
separate question of whether we should provide a mechanism for
declaring steps that have a variable number of ports, let’s leave that
aside for the moment.)

2. Pipelines can be declared to have any number of input or output
ports. When you’re calling them, the constraints are the same as for
atomic steps. I don’t think that’s controversial either.

3. Subpipeline containers (group, when, otherwise, catch), can declare
any number of outputs, subject to consistency constraints.

Suppose we relaxed those constraints. Consider:

  <p:try>
    <p:group>
      <p:output port="animal"/>
      …
    </p:group>
    <p:catch>
      <p:output port="animal"/>
      <p:output port="plant"/>
      …
    </p:catch>
  </p:try>

Currently, that’s an error. What if we said it wasn’t an error. What
if we said that the “try” has two outputs: “animal” and “plant”. In
the case where the “group” succeeds, the output on “plant” is simply
the empty sequence.

Similarly, in the p:choose case:

  <p:choose>
    <p:when test="…">
      <p:output port="animal"/>
      <p:output port="plant"/>
      …
    </p:when>
    <p:when test="…">
      <p:output port="plant"/>
      <p:output port="mineral"/>
      …
    </p:when>
    <p:otherwise>
      <p:output port="animal"/>
      <p:output port="mineral"/>
      …
    </p:otherwise>
  </p:choose>

We could say that this choose has three outputs, “animal”, “plant”,
and “mineral”. One of them will produce the empty sequence, depending
on which branch is chosen at runtime, but it’s still there.

Users can make all the signatures the same, in which case they’ll get
the same behavior as in 1.0. And of course, if you connect something
to a port that will sometimes be empty, the thing you connect to it
had better take a sequence.

This came up in the course of thinking about a “finally” clause for
try/catch:

  <p:try>
    <p:group>
      <p:output port="result"/>
      …
    </p:group>
    <p:catch>
      <p:output port="result"/>
      …
    </p:catch>
    <p:finally>
      <p:output port="finally"/>
      …
    </p:finally>
  </p:try>

In the current try/catch and choose/when designs, exactly one branch
will run, so the output you get is from whichever branch
(group/catch/when/otherwise) actually ran.

But if we introduce finally, *two* branches will run. If finally has
to put it’s output on “result” (to make the signatures match), then
you’re going to get multiplexed results on the result output port.

There are a few options:

1. Forbid the finally branch from having any output. That seems to
limit finally pretty substantially.

2. Require that group/catch also have a “finally” output port to keep
the signatures the same. That’s a real inconvenience for users.

3. Create a magic port: say that the “finally” port always exists and
is magically plumbed to the finally branch. (Yuck.)

4. Relax the constraints as I’ve described above.

On the whole, I think I prefer 4. But maybe I’m overlooking something.

                                        Be seeing you,
                                          norm

-- 
Norman Walsh
Lead Engineer
MarkLogic Corporation
Phone: +1 512 761 6676
www.marklogic.com

Received on Sunday, 3 September 2017 18:46:04 UTC