[
https://issues.apache.org/jira/browse/TINKERPOP-3178?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18011046#comment-18011046
]
ASF GitHub Bot commented on TINKERPOP-3178:
-------------------------------------------
Cole-Greer commented on code in PR #3170:
URL: https://github.com/apache/tinkerpop/pull/3170#discussion_r2243794006
##########
docs/src/dev/provider/gremlin-semantics.asciidoc:
##########
@@ -1145,6 +1146,77 @@
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/o
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/ServiceRegistry.java[ServiceRegistry],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#call-step[reference]
+[[choose-step]]
+=== choose()
+
+*Description:* A branch step that routes the traverser to different paths
based on a choice criterion.
+
+*Syntax:* `choose(Traversal|T choice)` | `choose(Traversal|P choice, Traversal
trueChoice)` |`choose(Traversal|P choice, Traversal trueChoice, Traversal
falseChoice)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |Y |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `choice` - A `Traversal`, or `T` that produces a value used to determine
which option to take. In the `if-then` forms, this value may be a `P` to
determine `true` or `false`.
+* `trueChoice` - The traversal to take if the predicate traversal returns a
value (has a next element).
+* `falseChoice` - The traversal to take if the predicate traversal returns no
value (has no next element).
+
+*Modulation:*
+
+* `option(pickToken, traversalOption)` - Adds a traversal option to the
`choose` step. The `pickToken` is matched
+against the result of the choice traversal. The `pickToken` may be a literal
value, a predicate `P`, a `Traversal`
+(whose first returned value is used for matching) or a `Pick` enum value. If a
match is found, the traverser is routed
+to the corresponding `traversalOption`.
+
+*Considerations:*
+
+The `choose()` step is a branch step that routes the traverser to different
paths based on a choice criterion. There are
+two main forms of the `choose()` step:
+
+1. *if-then form*: `choose(predicate, trueChoice, falseChoice)` - If the
predicate traversal or `P` returns a value
+(has a next element), the traverser is routed to the trueChoice traversal.
Otherwise, it is routed to the falseChoice
+traversal. If the predicate is unproductive or if the falseChoice is not
specified, then the traverser passes through.
+
+2. *switch form*: `choose(choice).option(pickValue, resultTraversal)` - The
choice which may be a `Traversal` or
+`T` produces a value that is matched against the pickValue of each option. If
a match is found, the traverser is routed
+to the corresponding resultTraversal and no further matches are attempted. If
no match is found then the traverser is
+filtered, but, for these cases, the `Pick.none` option can be provided to
match those cases. If the choiceTraversal is
+unproductive, then the traverser passes through by default or can be matched
on `Pick.unproductive`.
+
+The `choose()` step can be used with the following special `Pick` tokens:
+
+* `Pick.none` - Used to specify a default option when no other options match.
+* `Pick.unproductive` - Used when the choice traversal produces no value.
+
+`choose` does not allow more than one traversal to be assigned to a single
`Pick`. The last `Pick` assigned via `option`
+is the one that will be used.
+
+The `choose()` step ensures that only one option is selected for each
traverser, unlike other branch steps like
+`union()` that can route a traverser to multiple paths. As it is like
`union()`, note that each `option` stream will
+behave like one:
+
+[source,text]
Review Comment:
We don't yet have a precedent for traversal examples in the step semantics
docs. Might be preferable to execute these examples via
`[gremlin-groovy,modern]`
##########
docs/src/dev/provider/gremlin-semantics.asciidoc:
##########
@@ -1145,6 +1146,77 @@
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/o
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/ServiceRegistry.java[ServiceRegistry],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#call-step[reference]
+[[choose-step]]
+=== choose()
+
+*Description:* A branch step that routes the traverser to different paths
based on a choice criterion.
+
+*Syntax:* `choose(Traversal|T choice)` | `choose(Traversal|P choice, Traversal
trueChoice)` |`choose(Traversal|P choice, Traversal trueChoice, Traversal
falseChoice)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |Y |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `choice` - A `Traversal`, or `T` that produces a value used to determine
which option to take. In the `if-then` forms, this value may be a `P` to
determine `true` or `false`.
+* `trueChoice` - The traversal to take if the predicate traversal returns a
value (has a next element).
+* `falseChoice` - The traversal to take if the predicate traversal returns no
value (has no next element).
+
+*Modulation:*
+
+* `option(pickToken, traversalOption)` - Adds a traversal option to the
`choose` step. The `pickToken` is matched
+against the result of the choice traversal. The `pickToken` may be a literal
value, a predicate `P`, a `Traversal`
+(whose first returned value is used for matching) or a `Pick` enum value. If a
match is found, the traverser is routed
+to the corresponding `traversalOption`.
+
+*Considerations:*
+
+The `choose()` step is a branch step that routes the traverser to different
paths based on a choice criterion. There are
+two main forms of the `choose()` step:
+
+1. *if-then form*: `choose(predicate, trueChoice, falseChoice)` - If the
predicate traversal or `P` returns a value
+(has a next element), the traverser is routed to the trueChoice traversal.
Otherwise, it is routed to the falseChoice
+traversal. If the predicate is unproductive or if the falseChoice is not
specified, then the traverser passes through.
+
+2. *switch form*: `choose(choice).option(pickValue, resultTraversal)` - The
choice which may be a `Traversal` or
+`T` produces a value that is matched against the pickValue of each option. If
a match is found, the traverser is routed
+to the corresponding resultTraversal and no further matches are attempted. If
no match is found then the traverser is
+filtered, but, for these cases, the `Pick.none` option can be provided to
match those cases. If the choiceTraversal is
+unproductive, then the traverser passes through by default or can be matched
on `Pick.unproductive`.
+
+The `choose()` step can be used with the following special `Pick` tokens:
+
+* `Pick.none` - Used to specify a default option when no other options match.
+* `Pick.unproductive` - Used when the choice traversal produces no value.
+
+`choose` does not allow more than one traversal to be assigned to a single
`Pick`. The last `Pick` assigned via `option`
+is the one that will be used.
+
+The `choose()` step ensures that only one option is selected for each
traverser, unlike other branch steps like
+`union()` that can route a traverser to multiple paths. As it is like
`union()`, note that each `option` stream will
+behave like one:
+
+[source,text]
+----
+gremlin> g.V().union(__.has("name", "vadas").values('age').fold(),
__.has('name',neq('vadas')).values('name').fold())
+==>[27]
+==>[marko,lop,josh,ripple,peter]
+gremlin> g.V().choose(__.has("name", "vadas"), __.values('age').fold(),
__.values('name').fold())
+==>[27]
+==>[marko,lop,josh,ripple,peter]
+----
+
+*Exceptions*
+
+* `IllegalArgumentException` - If `Pick.any` is used as an option token, as
only one option per traverser is allowed.
+* `IllegalArgumentException` - If the same pick token is used more than once.
Review Comment:
This does not appear to be the case at the moment:
```
gremlin> g.V().choose(values("age"))
.option(29, constant("match"))
.option(none, constant("none"))
.option(unproductive, constant("unproductive"))
.option(29, constant("match2"))
.option(none, constant("none2"))
.option(unproductive, constant("unproductive2"))
==>match
==>none
==>unproductive
==>none
==>unproductive
==>none
```
##########
docs/src/dev/provider/gremlin-semantics.asciidoc:
##########
@@ -1145,6 +1146,77 @@
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/o
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/ServiceRegistry.java[ServiceRegistry],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#call-step[reference]
+[[choose-step]]
+=== choose()
+
+*Description:* A branch step that routes the traverser to different paths
based on a choice criterion.
+
+*Syntax:* `choose(Traversal|T choice)` | `choose(Traversal|P choice, Traversal
trueChoice)` |`choose(Traversal|P choice, Traversal trueChoice, Traversal
falseChoice)`
+
+[width="100%",options="header"]
+|=========================================================
+|Start Step |Mid Step |Modulated |Domain |Range
+|N |Y |Y |`any` |`any`
+|=========================================================
+
+*Arguments:*
+
+* `choice` - A `Traversal`, or `T` that produces a value used to determine
which option to take. In the `if-then` forms, this value may be a `P` to
determine `true` or `false`.
+* `trueChoice` - The traversal to take if the predicate traversal returns a
value (has a next element).
+* `falseChoice` - The traversal to take if the predicate traversal returns no
value (has no next element).
+
+*Modulation:*
+
+* `option(pickToken, traversalOption)` - Adds a traversal option to the
`choose` step. The `pickToken` is matched
+against the result of the choice traversal. The `pickToken` may be a literal
value, a predicate `P`, a `Traversal`
+(whose first returned value is used for matching) or a `Pick` enum value. If a
match is found, the traverser is routed
+to the corresponding `traversalOption`.
+
+*Considerations:*
+
+The `choose()` step is a branch step that routes the traverser to different
paths based on a choice criterion. There are
+two main forms of the `choose()` step:
+
+1. *if-then form*: `choose(predicate, trueChoice, falseChoice)` - If the
predicate traversal or `P` returns a value
+(has a next element), the traverser is routed to the trueChoice traversal.
Otherwise, it is routed to the falseChoice
+traversal. If the predicate is unproductive or if the falseChoice is not
specified, then the traverser passes through.
+
+2. *switch form*: `choose(choice).option(pickValue, resultTraversal)` - The
choice which may be a `Traversal` or
+`T` produces a value that is matched against the pickValue of each option. If
a match is found, the traverser is routed
+to the corresponding resultTraversal and no further matches are attempted. If
no match is found then the traverser is
+filtered, but, for these cases, the `Pick.none` option can be provided to
match those cases. If the choiceTraversal is
+unproductive, then the traverser passes through by default or can be matched
on `Pick.unproductive`.
+
+The `choose()` step can be used with the following special `Pick` tokens:
+
+* `Pick.none` - Used to specify a default option when no other options match.
+* `Pick.unproductive` - Used when the choice traversal produces no value.
+
+`choose` does not allow more than one traversal to be assigned to a single
`Pick`. The last `Pick` assigned via `option`
Review Comment:
Current implementation appears to favor the first match, not the last match.
```suggestion
`choose` does not allow more than one traversal to be assigned to a single
`Pick`. The first `Pick` assigned via `option`
```
> Clarify choose() with consistent semantics
> ------------------------------------------
>
> Key: TINKERPOP-3178
> URL: https://issues.apache.org/jira/browse/TINKERPOP-3178
> Project: TinkerPop
> Issue Type: Improvement
> Components: process
> Affects Versions: 3.7.3
> Reporter: Stephen Mallette
> Priority: Major
> Labels: breaking
>
> h3. Match only a single case in {{choose()}}
> {code}
> gremlin> g.V().hasLabel('person').choose(values('age')).option(27,
> constant('x')).option(27, constant('y')).option(none, constant('z'))
> ==>z
> ==>x
> ==>y
> ==>z
> ==>z
> {code}
> There should be only 4 results above, one for each person, but {{choose}} is
> matching twice on 27. {{choose}} should match the first item it finds only
> and no fall through.
> h3. Consistent behavior for unmatched inputs
> {code}
> // This passes through unmatched inputs
> g.V().choose(values('age'), values('age'))
> ==>29
> ==>27
> ==>v[3]
> ==>32
> ==>v[5]
> ==>35
> // This throws exception for unmatched inputs
> g.V().choose(values('age')).option(27, out()).option(none, in()).path()
> The provided traverser does not map to a value:
> v[3][TinkerVertex]->[PropertiesStep([age],value)][DefaultGraphTraversal]
> parent[[TinkerGraphStep(vertex,[]),
> ChooseStep([PropertiesStep([age],value)],[[none, [[VertexStep(IN,vertex),
> EndStep]]], [(eq(27)), [VertexStep(OUT,vertex), EndStep]]]), PathStep]]
> {code}
> Change the switch form to behave like the if-then form.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)