Matt Frantz created TINKERPOP3-716:
--------------------------------------
Summary: subroutine step
Key: TINKERPOP3-716
URL: https://issues.apache.org/jira/browse/TINKERPOP3-716
Project: TinkerPop 3
Issue Type: Improvement
Components: process
Reporter: Matt Frantz
Assignee: Marko A. Rodriguez
In our application, we build complex traversals. We use a modular technique in
which lower-level traversals are used to compose higher-level traversals. For
example, we might have an API like this:
{code}
void computeFoo(GraphTraversal t);
{code}
The assumption is that the "root" traversal has some state in the form of its
traverser and path (and possible sack and side effects, although we're not
using those at the moment). Importantly, all of this state is not fully
realized, as the goal is to build another traversal before executing it all at
once. To use the "foo" traversal in the "bar" traversal, I might do this:
{code}
void computeBar(GraphTraversal t) {
// Perform some part of the "bar" calculation, including setting up the
parameters of "foo"
t.out()...;
// Attach the "foo" logic.
computeFoo(t);
// Continue with more "bar" logic.
t.blah()...;
}
{code}
In the implementation of these modular traversals, we end up exposing certain
implementation details, especially in the form of labeled steps (path keys).
It is often the case that we don't necessarily want to leak this state. We
often want these traversals to operate as if they were single steps, discarding
any evidence of graph wandering that might have occurred.
What if there were a step which acted as a "stack" for the path? (It might
also act as a stack for the sack; we figured we would need that if we ever
decide to use sack.) Not only would this provide encapsulation, it would allow
the path to be pruned and thus improve runtime efficiency.
We want traversal subroutines. How about this signature?
{code}
GraphTraversal sub(Traversal subTraversal);
{code}
What this would do is guarantee that no path state (or sack state) would
escape. The only effect would be on the traverser. I think it could be
implemented using a {{MapStep}}, or possibly {{FlatMapStep}} in order to
realize a subTraversal that branches.
What state would subTraversal have access to? By default, it could only see
the traverser. It has its own key namespace for the path, so it cannot see the
outer path. It has its own sack. It should probably have its own side effect
key namespace, too.
If you want to opt-in state into the subTraversal, then perhaps you could list
the keys to form a pseudo-path:
{code}
GraphTraversal sub(Traversal subTraversal, String...stepOrSideEffectLabels);
{code}
One of the interesting things that this might provide (eventually) is the
ability to hang OLTP traversal off of OLAP traversals. I had discussed this
need a while ago in the context of vertices that act as OLAP "computation
loci". A "sub" could use a different engine, and thus embed a standard
traversal within a computer traversal.
This would change our modular programming paradigm. We could safely redesign
each module to produce an anonymous traversal like so:
{code}
GraphTraversal computeFoo();
GraphTraversal computeBar() {
// Perform some part of the "bar" calculation, including setting up the
parameters of "foo"
GraphTraversal t = __.out()...;
// Attach the "foo" logic.
t.sub(computeFoo(t));
// Continue with more "bar" logic.
return t.in()...;
}
{code}
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)