////
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements.  See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
////
[[gremlin-semantics]]
= Gremlin Semantics

image:tinkerpop-meeting-room.png[]

This section provides details on Gremlin language operational semantics. Describing these semantics and reinforcing
them with tests in the Gremlin test suite makes it easier for providers to implement the language and for the
TinkerPop Community to have better consistency in their user experiences. While the general Gremlin test suite offers
an integrated approach to testing Gremlin queries, the `@StepClassSemantics` oriented tests found
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features[here] are especially focused to the
definitions found in this section. References to the location of specific tests can be found throughout the
sub-sections below.

== Types

The TinkerPop query execution runtime is aligned with Java primitives and handles the following primitive types:

* Boolean
* Integer
  ** Byte (int8)
  ** Short (int16)
  ** Integer (int32)
  ** Long (int64)
  ** BigInteger
* Decimal
  ** Float (32-bit) (including +/-Infinity and NaN)
  ** Double (64-bit) (including +/-Infinity and NaN)
  ** BigDecimal
* String
* UUID
* Date
* `nulltype`
  ** Has only one value in its type space - the "undefined" value `null`

NOTE: TinkerPop has a bit of a JVM-centric view of types as it was developed within that ecosystem.

Graph providers may not support all of these types depending on the architecture and implementation. Therefore
TinkerPop must provide a way for Graph providers to override the behavior while it has its own default behavior. Also
when some types are not supported Graph providers needs to map unsupported types into supported types internally. This
mapping can be done in either information-preserving manner or non-preserving manner. Graph providers must tell which
mapping they support through `Graph.Features` as well as which types they support.

* Which primitive types are supported
  ** Boolean, Integer, Float, String, UUID and Date
  ** TinkerPop by default supports all of them
* Which integer types are supported
  ** TinkerPop by default supports int8 (Byte), int16 (Short), int32 (Integer), int64 (Long) and BigInteger in Java
* Which float types are supported
  ** TinkerPop by default supports all as float, double, and BigDecimal in Java

In addition to these, there are composite types as follows:

* Graph Element
** Vertex
** Edge
** VertexProperty
* Property (edge properties and meta properties)
** (Key, Value) pair
** Key is String, Value is any of the primitive types defined above
* Path
* List
* Map
* Map.Entry
* Set

=== Numeric Type Promotion

TinkerPop performs type promotion a.k.a type casting for Numbers. Numbers are Byte, Short, Integer, Long, Float,
Double, BigInteger, and BigDecimal. In general, numbers are compared using semantic equivalence, without regard for
their specific type, e.g. `1 == 1.0`.

For comparisons numeric types are promoted as follows:

* First determine whether to use floating point or not. If any numbers in the comparison are floating point then we
convert all of them to floating point.
* Next determine the maximum bit size of the numerics being compared.
* If any floating point are present:
** If the maximum bit size is 32 (up to Integer/Float), we compare as Float
** If the maximum bit size is 64 (up to Long/Double), we compare as Double
** Otherwise we compare as BigDecimal
* If no floating point are present:
** If the maximum bit size is 8 we compare as Byte
** If the maximum bit size is 16 we compare as Short
** If the maximum bit size is 32 we compare as Integer
** If the maximum bit size is 64 we compare as Long
** Otherwise we compare as BigInteger

BigDecimal and BigInteger may not be supported depending on the language and Storage, therefore the behavior of type
casting for these two types can vary depending on a Graph provider.

For numeric type mathematical operations (div/mul/add/sub), types are promoted as follows:

On math operations (when used in steps such as sum/sack) the highest common number class between
the two inputs is used. Any number being floating point forces a floating point result.
If an overflow occurs (either integer or floating-point), the method promotes the precision
by increasing the bit width, until a suitable type is found. If no suitable type exists
(e.g., for very large integers beyond 64-bit), an Arithmetic Exception is thrown.
For floating-point numbers, if double overflows, the result is Double.POSITIVE_INFINITY
or Double.NEGATIVE_INFINITY instead of an exception.

[[gremlin-semantics-concepts]]
== Comparability, Equality, Orderability, and Equivalence

This section of the document attempts to more clearly define the semantics for different types of value comparison
within the Gremlin language and reference implementation. There are four concepts related to value comparison:

**Equality**

Equality semantics is used by the equality operators (`P.eq/neq`) and contains operators derived from them
(`P.within/without`). It is also used for implicit `P.eq` comparisons, for example `g.V().has("age", 25)` - equality
semantics are used to look up vertices by `age` when considering the value.

**Comparability**

Comparability semantics is used by the compare operators (`P.lt/lte/gt/gte`) and operators derived from them
(`P.inside/outside/between`) and defines the semantics of how to compare two values.

**Orderability**

Orderability semantics defines how two values are compared in the context of an `order()` operation. These semantics
have important differences from Comparability.

**Equivalence**

Equivalence semantics are slightly different from Equality and are used for operations such as `dedup()` and `group()`.
Key differences include handling of numeric types and NaN.

Both Equality and Equivalence can be understood as complete, i.e. the result of equality and equivalence checks is
always either `TRUE` or `FALSE` (in particular, it never returns `nulltype` or throws an exception). Similarly,
Orderability can be also understood as complete - any two values can be compared without error for ordering purposes.
Comparability semantics are not complete with respect to traditional binary boolean semantics, as certain comparisons
cannot be proved as either `TRUE` or `FALSE`. Common examples of such cases are Comparability against `NaN`, cross-type
Comparability (e.g. `String` vs `Numeric`). For the purposes of Comparability within Gremlin, any such incomputable
comparison is defined to be `FALSE`, and traditional binary boolean semantics apply thereafter.

[[gremlin-semantics-equality-comparability]]
=== Equality and Comparability

<<Equality,Equality>> and <<Comparability,Comparability>> can be understood to be semantically aligned with one another.
As mentioned above, <<Equality,Equality>> is used for `P.eq/neq` (and derived predicates) and
<<Comparability,Comparability>> is used for `P.lt/lte/gt/gte` (and derived predicates).
If we define Comparability using a `compare()` function over `A` and `B` as follows:

[source,text]
----
If (A, B) are Comparable per Gremlin semantics, then:
  For A < B,  Comparability.compare(A, B) < 0
  For A > B,  Comparability.compare(A, B) > 0
  For A == B, Comparability.compare(A, B) == 0
If (A, B) not Comparable, then:
              Comparability.compare(A, B) => ERROR
----

Then we can define Equality using an `equals()` function over `A` and `B` that acts as a strict binary
reduction of `Comparability.compare(A, B) == 0`:

[source,text]
----
For any (A, B):
  Comparability.compare(A, B) == 0     implies Equality.equals(A, B) == TRUE
  Comparability.compare(A, B) <> 0     implies Equality.equals(A, B) == FALSE
  Comparability.compare(A, B) => ERROR implies Equality.equals(A, B) == FALSE
----

The following table illustrates how <<Equality,Equality>> and <<Comparability,Comparability>> operate under various
classes of comparison:

|===
|Class|Arguments|<<Comparability,Comparability>>|<<Equality,Equality>>

|Comparisons Involving `NaN`|`(NaN,X)` +

where `X` = any value, including `NaN`|`FALSE` +

Comparing `NaN` to anything (including itself) cannot be evaluated.|`FALSE`

|Comparisons Involving `null`|`(null,null)`|`compare() == 0`|`TRUE`
||`(null, X)`|`FALSE` +

Since `nulltype` is its own type, this falls under the umbrella of cross-type comparisons. |`FALSE`
|Comparisons within the same type family (i.e. String vs. String, Number vs. Number, etc.)|`(X, Y)` +

where `X` and `Y` of same type|Result of `compare()` depends on type semantics, defined below.|`TRUE` iff `compare() == 0`
|Comparisons across types (i.e. String vs. Number)|`(X, Y)` +

where `X` and `Y` of different type|`FALSE`|`FALSE`

|===

==== Equality and Comparability Semantics by Type

For <<Equality,Equality>> and <<Comparability,Comparability>> evaluation of values within the same type family, we
define the semantics per type family as follows.

===== Number

Numbers are compared using type promotion, described above. As such, `1 == 1.0`.

Edge cases:

* `-0.0 == 0.0 == +0.0`
* `+INF == +INF`,  `-INF == -INF`,  `-INF != +INF`
** `Float.±Infinity` and `Double.±Infinity` adhere to the same type promotion rules.
* As described above `NaN` is not <<Equality,Equal>> and not <<Comparability,Comparable>> to any Number (including itself).

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Equality.feature[Equality Tests - Scenarios prefixed with "Primitives_Number_"]

===== nulltype

As described in the table above, `null == null`, but is not <<Equality,Equal>> and not <<Comparability,Comparable>> to
any non-`null` value.

===== Boolean

For Booleans, `TRUE == TRUE`, `FALSE == FALSE`, `TRUE != FALSE`, and `FALSE < TRUE`.

===== String

We assume the common lexicographical order over unicode strings. `A` and `B` are compared lexicographically, and
`A == B` if `A` and `B` are lexicographically equal.

===== UUID

UUID is evaluated based on its String representation. However, `UUID("b46d37e9-755c-477e-9ab6-44aabea51d50")` and the
String `"b46d37e9-755c-477e-9ab6-44aabea51d50"` are not <<Equality,Equal>> and not <<Comparability,Comparable>>.

===== Date

Dates are evaluated based on the numerical comparison of Unix Epoch time.

===== Graph Element (Vertex / Edge / VertexProperty)

If they are the same type of Element, these are compared by the value of their `T.id` according to the semantics for
the particular primitive type used for ids (implementation-specific). Elements of different types are
not <<Equality,Equal>> and not <<Comparability,Comparable>>.

===== Property

Properties are compared first by key (String semantics), then by value, according to the semantics for the particular
primitive type of the value. Properties with values in different type families are
not <<Equality,Equal>> and not <<Comparability,Comparable>>.

===== List

Lists are compared pairwise, element-by-element, in their natural list order. For each element, if the pairs are
<<Equality and Comparability,Equal>>, we simply move on to the next element pair until we encounter a pair which is not
comparable, or whose `Comparability.compare()` value is non-zero, and we return that value. Lists can be evaluated
for <<Equality and Comparability,Equality and Comparability>> even if they contain multiple types of elements, so long
as their elements are pairwise comparable per <<Equality and Comparability,Equality/Comparability>> semantics. During
this element by element comparison, if iteration `A` exhausts its elements before iteration `B` then `A < B`, and
vice-versa.

Empty lists are equal to other empty lists and less than non-empty lists.

|===
|`A`|`B`|`compare(A,B)`|`P`|Reason

|`[]`|`[]`|`0`|`P.eq`|empty lists are equal
|`[]`|`[1]`|`-1`|`P.lt`|empty < non-empty
|`[1]`|`[]`|`1`|`P.gt`|non-empty > empty
|`[1,2,3]`|`[1,2,3]`|`0`|`P.eq`|pairwise equal
|`[1,2,3]`|`[1,2,4]`|`-1`|`P.lt`|pairwise equal until last element: `3 < 4`
|`[1,2,3]`|`[1,2,3,4]`|`-1`|`P.lt`|`A` exhausts first
|`[1,2,3,4]`|`[1,2,3]`|`1`|`P.gt`|`B` exhausts first
|`[1,2]`|`[1.0,2.0]`|`0`|`P.eq`|type promotion
|`[1,"a"]`|`[1,"b"]`|`-1`|`P.lt`|pairwise <<Comparability,Comparable>> and `"a" < "b"`
|`[1]`|`["a"]`|`ERROR`|`P.neq`|cross-type comparison
|===

===== Path

<<Equality and Comparability,Equality and Comparability>> semantics for `Paths` are similar to those for `Lists`, described above (though
`Paths` and `Lists` are still of different types and thus not <<Equality,Equal>> and not <<Comparability,Comparable>>).

===== Set

`Sets` are compared pairwise, element-by-element, in the same way as `Lists`, but they are compared in sorted order
using <<Orderability,Orderability>> semantics to sort (described further below). We use <<Orderability,Orderability>>
semantics for ordering so that `Sets` containing multiple element types can be properly sorted before being compared.

For example:

|===
|`A`|`B`|`compare(A,B)`|`P`|Reason

|`{1, 2}`|`{2, 1}`|`0`|`P.eq`|sort before compare
|`{1, "foo"}`|`{"foo", 1}`|`0`|`P.eq`|we use <<Orderability,Orderability>> semantics to sort across types
|===

Sets do introduce a bit of semantic stickiness, in that on the one hand they do respect type promotion semantics for
Equality and Comparability:

[source,text]
----
{1, 2} == {1.0, 2.0}
----

But on the other hand they also allow two elements that would be equal (and thus duplicates) according to type
promotion:

[source,text]
----
{1, 1.0, 2} is a valid set and != {1, 2}
----

We allow some "wiggle-room" in the implementation for providers to decide how to handle this logical inconsistency. The
reference implementation allows for semantically equivalent numerics to appear in a set (e.g `{1, 1.0}`), while at the
same time evaluating the same semantically equivalent numerics as equal during pairwise comparison across sets (e.g.
`{1,2} == {1.0,2.0}`).

===== Map

'Map' semantics can be thought of as similar to `Set` semantics for the entry set the comprises the `Map`. So again,
we compare pairwise, entry-by-entry, in the same way as `Lists`, and again, we first sort the entries using
<<Orderability,Orderability>> semantics. Map entries are compared first by key, then by value using the
<<Equality and Comparability Semantics by Type,Equality and Comparability>> semantics that apply to the specific type
of key and value.

Maps semantics have the same logical inconsistency as set semantics, because of type promotion. Again, we leave room
for providers to decide how to handle this in their implementation. The reference implementation allows for semantically
equivalent keys to appear in a map (e.g. `1` and `1.0` can both be keys in the same map), but when comparing maps we
treat pairwise entries with semantically equivalent keys as the same.

==== Comparability of Types

The `P.typeOf()` predicate enables type-based filtering in TinkerPop using inheritance-aware comparison, where a value
matches if it is the specified type or any of its subtypes.

===== GType Enums

Based on the support type space, we have defined a `GType` enum, which contains a set of enumerations that is used for
type casting (`asNumber()`) and comparison (`P.typeOf()`) operations.

* **Numeric types**: `INT`, `LONG`, `DOUBLE`, `FLOAT`, `BYTE`, `SHORT`, `BIGDECIMAL`, `BIGINT`
* **General types**: `STRING`, `BOOLEAN`, `CHAR`, `UUID`, `BINARY`
* **Collection types**: `LIST`, `SET`, `MAP`
* **Graph types**: `VERTEX`, `EDGE`, `PROPERTY`, `VPROPERTY`, `PATH`, `TREE`, `GRAPH`
* **Temporal types**: `DATETIME`, `DURATION`
* **Special types**: `NULL`, `NUMBER` (supertype for all numeric types)

===== GlobalTypeCache

Providers can register custom types outside the TinkerPop type space using the `GlobalTypeCache`, making them available
for `P.typeOf(String)` filtering. Unregistered string inputs will throw an `IllegalArgumentException`.

The `registerDataType()` method registers the class's simple name by default, or accepts a custom string name. Providers
should use PascalCase following Java conventions and prefix type names to avoid conflicts
(e.g., `ProviderPrefix:SimpleTypeName`).

Do note that the type cache only enables type recognition for filtering. Custom types still require separate
serialization support - clients without custom serializers cannot deserialize these types.

[[gremlin-semantics-orderability]]
=== Orderability

<<Equality and Comparability,Equality and Comparability>> were described in depth in the sections above, and their
semantics map to the `P` predicates. <<Comparability,Comparability>> in particular is limited to
comparison of values within the same type family. Comparability is complete within a given type (except for `NaN`,
which results in `FALSE` for any comparison), but returns `FALSE` for comparisons across types (e.g., an integer cannot
be compared to a string).

Orderability semantics are very similar to Comparability for the most part, except that Orderability will never result
in `ERROR` for comparison of any two values - even if two values are incomparable according to Comparability semantics
we will still be able to determine their respective order. This allows for a total order across all Gremlin values. In
the reference implementation, any step using `Order.asc` or `Order.desc` (e.g. OrderGlobalStep, OrderLocalStep) will
follow these semantics.

To achieve this globally complete order, we need to address any cases in Comparability which are incomputable, we must
define a global order across type families, and we must provide semantics for ordering "unknown"
values (for cases of in-process JVM implementations, like the TinkerGraph).

We define the type space, and the global order across the type space as follows:

[source,text]
----
1.  nulltype
2.  Boolean
3.  Number
4.  Date
5.  String
6.  Vertex
7.  Edge
8.  VertexProperty
9.  Property
10. Path
11. Set
12. List
13. Map
14. Unknown
----

Values in different type spaces will be ordered according to their priority (e.g. all Numbers < all Strings).

Within a given type space, Orderability determines if two values are ordered at the same position or one value is
positioned before or after the another. When the position is identical, which value comes first (in other words,
whether it should perform stable sort) depends on graph providers' implementation.

To allow for this total ordering, we must also address the cases in <<Equality and Comparability,Comparability>> where
the comparison is incomputable:

|===
|Incomputable Scenario|Comparability|Orderability

|Comparison against `NaN`|`NaN` not comparable to anything, including itself.|`NaN` appears after `+Infinity` in the numeric type space.
|Comparison across types|Cannot compare values of different types. This includes the `nulltype`.|Subject to a total
type ordering where every value of type A appears before or after every value of Type B per the priorty list above.
|===

==== Key differences from Comparability

One key difference to note is that we use Orderability semantics to compare values within containers (`List`, `Set`,
`Path`, `Map`, `Property`) rather than using Comparability semantics (i.e. Orderability all the way down).

===== Numeric Ordering

Same as Comparability, except `NaN` is equivalent to `NaN` and is greater than all other Numbers, including `+Infinity`.
Additionally, because of type promotion (`1` == `1.0`), numbers of the same value but of different numeric types will
not have a stable sort order (`1` can appear either before or after `1.0`).

===== Property

Same as Comparability, except Orderability semantics are used for the property value.

===== Iterables (Path, List, Set, Map)

Same as Comparability, except Orderability semantics apply for the pairwise element-by-element comparisons.

===== Unknown Types

For Orderability semantics, we allow for the possibility of "unknown" types. If the "unknown" arguments are of the same
type, we use `java.lang.Object#equals()` and `java.lang.Comparable` (if implemented) to determine their natural order.
If the unknown arguments are of different types or do not define a natural order, we order first by Class,
then by `Object.toString()`.

[[gremlin-semantics-equivalence]]
=== Equivalence

Equivalence defines how TinkerPop deals with two values to be grouped or de-duplicated. Specifically it is necessary
for the `dedup()` and `group()` steps in Gremlin.

For example:

[source,text]
----
// deduplication needs equivalence over two property values
gremlin> g.V().dedup().by("name")
// grouping by equivalence over two property values
gremlin> g.V().group().by("age")
----

Like Equality, Equivalence checks always return `true` or `false`, never `nulltype` or `error`, nor do they produce
exceptions. For the most part Equivalence and Equality are the same, with the following key differences:

* Equivalence ignores type promotion semantics, i.e. two values of different types (e.g. 2^^int vs. 2.0^^float) are
always considered to be non-equivalent.
* `NaN` Equivalence is the reverse of Equality: `NaN` is equivalent to `NaN` and not
Equivalent to any other Number.

=== Further Reference

==== Mapping for P

The following table maps the notions proposed above to the various `P` operators:

[%header]
|================
|Predicate|Concept
|P.eq     |Equality
|P.neq    |Equality
|P.within |Equality
|P.without|Equality
|P.lt     |Comparability
|P.gt     |Comparability
|P.lte    |Equality, Comparability
|P.gte    |Equality, Comparability
|P.inside |Comparability
|P.outside|Comparability
|P.between|Equality, Comparability
|================

==== See Also

link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Equality.feature[Equality Tests],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Comparability.feature[Comparability Tests]

== Steps

While TinkerPop has a full test suite for validating functionality of Gremlin, tests alone aren't always exhaustive or
fully demonstrative of Gremlin step semantics. It is also hard to simply read the tests to understand exactly how a
step is meant to behave. This section discusses the semantics for individual steps to help users and providers
understand implementation expectations.

[[adde-step]]
=== addE()

*Description:* Adds an edge to the graph.

*Syntax:* `addE(String edgeLabel)` | `addE(Traversal<?, String> edgeLabelTraversal)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|Y |Y |`from()`/`to()` |`any` |`Edge`
|=========================================================

*Arguments:*

* `edgeLabel` - The label of the edge to add.
* `edgeLabelTraversal` - A traversal that produces the label of the edge to add.

*Modulation:*

* `from()` - Specifies the source vertex for the edge.
* `to()` - Specifies the target vertex for the edge.

*Considerations:*

The `addE()` step can be used as both a start step and a mid-traversal step. When used as a start step, both `from()`
and `to()` must be specified. When used as a mid-traversal step, the current traverser becomes the source vertex and
only `to()` needs to be specified.

The gremlin-lang grammar only permits `Traversal` and `String` (alias for `__.select(String)`) arguments in `from()` and
`to()`. The `Traversal` must either produce a `Vertex` which is attachable to the graph, or it must produce the id of an
existing `Vertex` in the graph. `GraphTraversal` implementations in GLVs may optionally support `from(Vertex)` and
`to(Vertex)` as syntactic sugar. If translating to gremlin-lang scripts, these sugared modulators must be converted to
`from(__.V(vertex.id()))` or `from(__.constant(vertex.id()))` (and equivalents for `to()`).

*Exceptions*

* If the edge label is null, an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStartStep.java[source (start)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addedge-step[reference]

[[addv-step]]
=== addV()

*Description:* Adds a vertex to the graph.

*Syntax:* `addV()` | `addV(String vertexLabel)` | `addV(Traversal<?, String> vertexLabelTraversal)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|Y |Y |N |`any` |`Vertex`
|=========================================================

*Arguments:*

* `vertexLabel` - The label of the vertex to add.
* `vertexLabelTraversal` - A traversal that produces the label of the vertex to add.

*Modulation:*

None

*Considerations:*

The `addV()` step can be used as both a start step and a mid-traversal step. If no label is provided, the default
vertex label for the graph will be used.

*Exceptions*

* If the vertex label is null, an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStartStep.java[source (start)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#addvertex-step[reference]

[[all-step]]
=== all()

*Description:* Filters array data from the traversal stream if all of the array's items match the supplied predicate.

*Syntax:* `all(P predicate)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`List`/`array`/`Iterable`/`Iterator` |`List`/`array`/`Iterable`/`Iterator`
|=========================================================

*Arguments:*

* `predicate` - The predicate to use to test each value in the array data.

*Modulation:*

None

*Considerations:*

Each value will be tested using the supplied predicate. Empty lists always pass through and null/non-list traversers
will be filtered out of the Traversal Stream.

*Exceptions*

* A GremlinTypeErrorException will be thrown if one occurs and no other value evaluates to false.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AllStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#all-step[reference]

[[aggregate-step]]
=== aggregate()

*Description:* Collects all objects in the traversal into a collection.

*Syntax:* `aggregate(String sideEffectKey)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`any`
|=========================================================

*Arguments:*

* `sideEffectKey` - The name of the side-effect key that will hold the aggregated objects.

*Modulation:*

* `by()` - Determines how to transform the object before aggregating. If not specified, the object itself is used.

*Considerations:*

The `aggregate()` step is a side-effect step that collects objects but passes the traverser to the next step unchanged.
The aggregated objects can be accessed later using the `cap()` step.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/AggregateStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#aggregate-step[reference]

[[and-step]]
=== and()

*Description:* Ensures that all provided traversals yield a result.

*Syntax:* `and(Traversal<?, ?>... andTraversals)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

* `andTraversals` - One or more traversals that will be executed against the current object.

*Modulation:*

None

*Considerations:*

The `and()` step is a filter step that allows the traverser to pass if all of the provided traversals yield a result.
It follows the ternary boolean logic described in the <<gremlin-semantics-concepts,Ternary Boolean Logics>> section.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AndStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#and-step[reference]

[[any-step]]
=== any()

*Description:* Filters array data from the Traversal Stream if any of the array's items match the supplied predicate.

*Syntax:* `any(P predicate)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`List`/`array`/`Iterable`/`Iterator` |`List`/`array`/`Iterable`/`Iterator`
|=========================================================

*Arguments:*

* `predicate` - The predicate to use to test each value in the array data.

*Modulation:*

None

*Considerations:*

Each value will be tested using the supplied predicate. Empty lists, null traversers, and non-list traversers will be
filtered out of the Traversal Stream.

*Exceptions*

* A GremlinTypeErrorException will be thrown if one occurs and no other value evaluates to true.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/AnyStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#any-step[reference]

[[as-step]]
=== as()

*Description:* Labels a step for later access by steps that make use of such labels.

*Syntax:* `as(String stepLabel, String... stepLabels)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

* `stepLabel` - The label to assign to the step.
* `stepLabels` - Additional labels to assign to the step.

*Modulation:*

None

*Considerations:*

The `as()` step is not a real step, but a "step modulator" similar to `by()` and `option()`. It allows labeling a step
for later access by steps like `select()` and `match()`. A step can have any number of labels associated with it, which
is useful for referencing the same step multiple times in a future step.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/GraphTraversal.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#as-step[reference]

[[asBool-step]]
=== asBool()

*Description:* Parse the value of the incoming traverser as boolean.

*Syntax:* `asBool()`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Number`/`String`/`Boolean` |`Boolean`
|=========================================================

*Arguments:*

None

Booleans are passed as is, numbers evaluate to `true` if non-zero, and `false` if zero or `NaN`. Strings only accept "true" or "false" (case-insensitive).

*Exceptions*

If the incoming traverser type is unsupported, a string other than "true" or "false", or `null`, then an `IllegalArgumentException` is thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsBoolStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asBool-step[reference]

[[asDate-step]]
=== asDate()

*Description:* Parse the value of incoming traverser as date. Supported ISO-8601 strings and Unix time numbers.

*Syntax:* `asDate()`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

None

Incoming date remains unchanged.

*Exceptions*

* If the incoming traverser is a non-String/Number/Date value then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsDateStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asDate-step[reference]

[[asNumber-step]]
=== asNumber()

*Description:* converts the incoming traverser to the nearest parsable type if no argument is provided, or to the desired numerical type, based on the number token (`N`) provided.

*Syntax:* `asNumber()` | `asNumber(GType typeToken)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Number`/`String` |`Number`
|=========================================================

*Arguments:*

* `typeToken` - The enum `GType` to denote the desired type to parse/cast to.

If no type token is provided, the incoming number remains unchanged.

*Exceptions*

* If any overflow occurs during narrowing of types, then an `ArithmeticException` will be thrown.
* If the incoming string cannot be parsed into a valid number format, then a `NumberFormatException` will be thrown.
* If the incoming traverser is a non-String/Number (including `null`) value then an `IllegalArgumentException` will be thrown.
* If the supplied type token is not a number type, then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsNumberStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asNumber-step[reference]

[[asString-step]]
=== asString()

*Description:* Returns the value of incoming traverser as strings, or if `Scope.local` is specified, returns each element inside
incoming list traverser as string.

*Syntax:* `asString()` | `asString(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`String`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual traverser, casting all (except `null`) to string. The `local` scope will behave like
`global` for everything except lists, where it will cast individual non-`null` elements inside the list into string and return a
list of string instead.

*Exceptions*

* If the incoming traverser is a `null` value then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AsStringLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#asString-step[reference]

[[barrier-step]]
=== barrier()

*Description:* Turns the lazy traversal pipeline into a bulk-synchronous pipeline.

*Syntax:* `barrier()` | `barrier(int maxBarrierSize)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

* `maxBarrierSize` - The maximum number of traversers that can be held in the barrier before being processed.

*Modulation:*

None

*Considerations:*

The `barrier()` step is useful in the following situations:
* When everything prior to `barrier()` needs to be executed before moving onto the steps after the `barrier()` (i.e., ordering).
* When "stalling" the traversal may lead to a "bulking optimization" in traversals that repeatedly touch many of the
same elements (i.e., optimizing).

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/NoOpBarrierStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#barrier-step[reference]

[[both-step]]
=== both()

*Description:* Maps a vertex to its adjacent vertices given the edge labels.

*Syntax:* `both(String... edgeLabels)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Vertex` |`Vertex`
|=========================================================

*Arguments:*

* `edgeLabels` - The edge labels to traverse. If no labels are provided, all edges are traversed.

*Modulation:*

None

*Considerations:*

The `both()` step is a vertex-centric step that traverses both incoming and outgoing edges from the current vertex to
adjacent vertices. It is equivalent to the union of `in()` and `out()`.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference]

[[bothe-step]]
=== bothE()

*Description:* Maps a vertex to its incident edges given the edge labels.

*Syntax:* `bothE(String... edgeLabels)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Vertex` |`Edge`
|=========================================================

*Arguments:*

* `edgeLabels` - The edge labels to traverse. If no labels are provided, all edges are traversed.

*Modulation:*

None

*Considerations:*

The `bothE()` step is a vertex-centric step that traverses both incoming and outgoing edges from the current vertex. It
is equivalent to the union of `inE()` and `outE()`.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/VertexStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference]

[[bothv-step]]
=== bothV()

*Description:* Maps an edge to its incident vertices.

*Syntax:* `bothV()`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Edge` |`Vertex`
|=========================================================

*Arguments:*

None

*Modulation:*

None

*Considerations:*

The `bothV()` step is an edge-centric step that traverses to both the incoming and outgoing vertices of the current
edge. It is equivalent to the union of `inV()` and `outV()`.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeVertexStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#vertex-steps[reference]

[[branch-step]]
=== branch()

*Description:* Splits the traverser to all the specified traversals.

*Syntax:* `branch(Traversal<?, M> branchTraversal)` | `branch(Function<Traverser<E>, M> function)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`option()` |`any` |`any`
|=========================================================

*Arguments:*

* `branchTraversal` - The traversal to branch the traverser to.
* `function` - The function to branch the traverser to.

*Modulation:*

* `option()` - Specifies the branch options for the traverser.

*Considerations:*

The `branch()` step is a general step that splits the traverser to all the child traversals provided to it. It's the
basis for more robust steps like `choose()` and `union()`. The branch step is typically used with the `option()` step
to specify the branch options.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/BranchStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#branch-step[reference]

[[cap-step]]
=== cap()

*Description:* Iterates the traversal up to itself and emits the sideEffect referenced by the provided key.

*Syntax:* `cap(String sideEffectKey, String... sideEffectKeys)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

* `sideEffectKey` - The side-effect to emit.
* `sideEffectKeys` - Other side-effects to emit.

*Modulation:*

None

*Considerations:*

The `cap()` step is a barrier step that iterates the traversal up to itself and emits the sideEffect referenced by the
provided key. If multiple keys are provided, then a `Map<String,Object>` of sideEffects is emitted.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SideEffectCapStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#cap-step[reference]

[[call-step]]
=== call()

*Description:* Provides support for provider-specific service calls.

*Syntax:* `call()` | `call(String service, Map params)` | `call(String service, Traversal childTraversal)` | `call(String service, Map params, Traversal childTraversal)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|Y |Y |`with()` |`any` |`any`
|=========================================================

*Arguments:*

* `service` - The name of the service call.
* `params` - A collection of static parameters relevant to the particular service call. Keys and values can be any
type currently supported by the Gremlin type system.
* `childTraversal` - A traversal used to dynamically build at query time a collection of parameters relevant to the service
call.

*Modulation:*

* `with(key, value)` - Sets an additional static parameter relevant to the service call. Key and value can be any
type currently supported by the Gremlin type system.
* `with(key, Traversal)` - Sets an additional dynamic parameter relevant to the service call. Key can be any
type currently supported by the Gremlin type system.

How static and dynamic parameters are merged is a detail left to the provider implementation. The reference implementation
(`CallStep`) uses effectively a "left to right" merge of the parameters - it starts with the static parameter `Map`
argument, then merges in the parameters from the dynamic `Traversal` argument, then merges in each `with` modulation
one by one in the order they appear.

Service calls in the reference implementation can be specified as `Start` (start of traversal), `Streaming`
(mid-traversal flat map step), and `Barrier` (mid-traversal barrier step). Furthermore, the `Barrier` type can be
all-at-once or with a maximum chunk size. A single service can support more than one of these modes, and if it does,
must provide semantics for how to configure the mode at query time via parameters.

Providers using the reference implementation to support service call with need to provide a `ServiceFactory` for each
named service that can create `Service` instances for execution during traversal. The `ServiceFactory` is a singleton
that is registered with the `ServiceRegistry` located on the provider `Graph`. The `Service` instance is local to
each traversal, although providers can choose to re-use instances across traversals provided there is no state.

*Considerations:*

Providers using the reference implementation can return `Traverser` output or raw value output - the `CallStep` will
handle either case appropriately. In the case of a `Streaming` service, where there is exactly one input to each
call, the reference implementation can preserve `Path` information by splitting the input `Traverser` when receiving
raw output from the call. In the case of `Barrier` however, it is the responsiblity of the `Service` to preserve
`Path` information by producing its own `Traversers` as output, since the `CallStep` cannot match input and ouput
across a barrier. The ability to split input `Traversers` and generate output is provided by the reference
implementation's `ServiceCallContext` object, which is supplied to the `Service` during execution.

There are three execution methods in the reference implementation service call API:

* `execute(ServiceCallContext, Map)` - execute a service call to start a traversal
* `execute(ServiceCallContext, Traverser, Map)` - execute a service call mid-traversal streaming (one input)
* `execute(ServiceCallContext, TraverserSet, Map)` - execute a service call mid-traversal barrier

The Map is the merged collection of all static and dynamic parameters. In the case of `Barrier` execution, notice
that there is one `Map` for many input. Since the `call()` API support dynamic parameters, this implies that all
input must reduce to the same set of parameters for `Barrier` execution. In the reference implementation, if more
than one parameter set is detected, this will cause an execution and the traversal will halt. Providers that
implement their own version of a call operation may decide on other strategies to handle this case - for example
it may be sensible to group traversers by Map in the case where multiple parameter sets are detected.

The no-arg version of the `call()` API is meant to be a directory service and should only be used to start a traversal.
The reference implementation provides a  default version, with will produce a list of service names or a service
description if run with `verbose=true`. Providers using the own implementation of the call operation must provide their
own directory listing service with the service name `"--list"`.

*Exceptions*

* If a named service does not support the execution mode implied by the traversal, for example, using a `Streaming` or
`Barrier` step as a traversal source, this will result in an `UnsupportedOperationException`.
* As mentioned above, dynamic property parameters (`Traversals`) that reduce to more than one property set for a chunk
of input is not supported in the reference implementation and will result in an `UnsupportedOperationException`.
* Use of the reference implementation's built-in directory service - `call()` or `call("--list")` - mid-traversal
will result in an `UnsupportedOperationException`.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CallStep.java[CallStep],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/structure/service/Service.java[Service],
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` or a `Pick` enum
value. `Traversal` is not allowed as a `pickToken` here and will lead to `IllegalArgumentException`. 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
passes through by default or can be matched on `Pick.none`. If the choiceTraversal is unproductive, then the traverser
passes through by default or can be matched on `Pick.unproductive`.

`choose` does not allow more than one traversal to be assigned to a single `Pick`. The first `Pick` assigned via
`option` is the one that will be used, similar to how the first pickValue match that is found is 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:

[gremlin-groovy,modern]
----
g.V().union(__.has("name", "vadas").values('age').fold(), __.has('name',neq('vadas')).values('name').fold())
g.V().choose(__.has("name", "vadas"), __.values('age').fold(), __.values('name').fold())
----

*Exceptions*

* `IllegalArgumentException` - If `Pick.any` is used as an option token, as only one option per traverser is allowed.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/ChooseStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#choose-step[reference]

[[combine-step]]
=== combine()

*Description:* Appends one list to the other and returns the result to the Traversal Stream.

*Syntax:* `combine(Object values)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable` |`List`
|=========================================================

*Arguments:*

* `values` - A list of items (as an Iterable or an array) or a traversal that will produce a list of items.

*Modulation:*

None

*Considerations:*

A list is returned after the combine operation is applied so duplicates are allowed. `Merge` can be used instead if
duplicates aren't wanted. This step only applies to list types which means that non-iterable types (including null)
will cause exceptions to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CombineStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#combine-step[reference],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#merge-step[merge() reference]

[[coin-step]]
=== coin()

*Description:* Filters traversers from the Traversal Stream based on a biased coin toss.

*Syntax:* `coin(double probability)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

* `probability` - The probability (between 0.0 and 1.0) that the traverser will pass through the filter.

*Modulation:*

None

*Considerations:*

Each traverser is subject to a random filter based on the provided probability. A probability of 0.0 means no
traversers pass through, while a probability of 1.0 means all traversers pass through.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/CoinStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#coin-step[reference]

[[concat-step]]
=== concat()

*Description:* Concatenates the incoming String traverser with the input String arguments, and return the joined String.

*Syntax:* `concat()` | `concat(String... concatStrings)` | `concat(Traversal concatTraveral, Traversal... otherConcatTraverals)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String` |`String`
|=========================================================

*Arguments:*

* `concatStrings` - Varargs of `String`. If one or more String values are provided, they will be concatenated together
with the incoming traverser. If no argument is provided, the String value from the incoming traverser is returned.
* `concatTraveral` - A `Traversal` whose must value resolve to a `String`. The first result returned from the traversal will
be concatenated with the incoming traverser.
* `otherConcatTraverals` - Varargs of `Traversal`. Each `Traversal` value must resolve to a `String`. The first result
returned from each traversal will be concatenated with the incoming traverser and the previous traversal arguments.

Any `null` String values will be skipped when concatenated with non-`null` String values. If two `null` value are
concatenated, the `null` value will be propagated and returned.

*Exceptions*

* If the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConcatStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#concat-step[reference]

[[dateAdd-step]]
=== dateAdd()

*Description:* Increase value of input Date.

*Syntax:* `dateAdd(DT dateToken, Integer value)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Date` |`Date`
|=========================================================

*Arguments:*

* `dateToken` - Date token enum. Supported values `second`, `minute`, `hour`, `day`.
* `value` - The number of units, specified by the DT Token, to add to the incoming values. May be negative for subtraction.

*Exceptions*

* If the incoming traverser is a non-Date value then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateAddStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#dateAdd-step[reference]

[[dateDiff-step]]
=== dateDiff()

*Description:* Returns the difference between two Dates in epoch time.

*Syntax:* `dateDiff(Date value)` | `dateDiff(Traversal dateTraversal)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Date` |`Date`
|=========================================================

*Arguments:*

* `value` - Date for subtraction.
* `dateTraversal` - The `Traversal` value must resolve to a `Date`. The first result returned from the traversal will be
subtracted with the incoming traverser.

If argument resolves as `null` then incoming date will not be changed.

*Exceptions*

* If the incoming traverser is a non-Date value then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DateDiffStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#dateDiff-step[reference]

[[dedup-step]]
=== dedup()

*Description:* Removes repeatedly seen results from the Traversal Stream.

*Syntax:* `dedup()` | `dedup(String... labels)` | `dedup(Scope scope, String... labels)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`any`
|=========================================================

*Arguments:*

* `scope` - Determines the scope in which `dedup` is applied.
The `global` scope will drop duplicate values across the global stream of traversers. The `local` scope operates at the
individual traverser level, and will remove duplicate values from within a collection.

* `labels` - If `dedup()` is provided a list of labels, then it will ensure that the de-duplication
is not with respect to the current traverser object, but to the path history of the traverser.

For Example:

[source,groovy]
----
g.V().as('a').out('created').as('b').in('created').as('c').
  dedup('a','b').select('a','b','c')
----

will filter out any such `a` and `b` pairs which have previously been seen.

*Modulation:*

* `by()` - Performs dedup according to the property specified in the by modulation. For example:
`g.V().dedup().by("name")` will filter out vertices with duplicate names.

*Considerations:*

* There is no guarantee that ordering of results will be preserved across a dedup step.
* There is no guarantee which element is selected as the survivor when filtering duplicates.

For example, given a graph with the following three vertices:

[width="100%",options="header"]
|=========================================================
|name |age
|Alex |38
|Bob |45
|Chloe |38
|=========================================================

and the traversal of:

[source,groovy]
----
g.V().order().by("name", Order.asc).
  dedup().by("age").values("name")
----

can return any of:

`["Alex", "Bob"]`, `["Bob", "Alex"]`, `["Bob", "Chloe"]`, or `["Chloe", "Bob"]`

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/DedupGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#dedup-step[reference]

[[difference-step]]
=== difference()

*Description:* Adds the difference of two lists to the Traversal Stream. 

*Syntax:* `difference(Object values)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable` |`Set`
|=========================================================

*Arguments:*

* `values` - A list of items (as an Iterable or an array) or a `Traversal` that will produce a list of items.

*Modulation:*

None

*Considerations:*

Set difference (`A-B`) is an ordered operation. The incoming traverser is treated as `A` and the provided argument is
treated as `B`. A set is returned after the difference operation is applied so there won't be duplicates. This step only
applies to list types which means that non-iterable types (including null) will cause exceptions to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DifferenceStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#difference-step[reference]

[[disjunct-step]]
=== disjunct()

*Description:* Adds the disjunct set to the Traversal Stream.

*Syntax:* `disjunct(Object values)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable` |`Set`
|=========================================================

*Arguments:*

* `values` - A list of items (as an Iterable or an array) or a `Traversal` that will produce a list of items.

*Modulation:*

None

*Considerations:*

A set is returned after the disjunct operation is applied so there won't be duplicates. This step only applies to list
types which means that non-iterable types (including null) will cause exceptions to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DisjunctStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#disjunct-step[reference]

[[element-step]]
=== element()

*Description:* Traverse from `Property` to its `Element`.

*Syntax:* `element()`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Property` |`Element`
|=========================================================

*Arguments:*

None

*Modulation:*

None

[[format-step]]
=== format()

*Description:* a mid-traversal step which will handle result formatting to string values.

*Syntax:* `format(String formatString)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`String`
|=========================================================

*Arguments:*

* `formatString` - Variables can be represented with `%{variable_name}` notation.
Positional arguments can be used as `%{_}` token. Can be used multiple times.
The variable values are used in the order that the first one will be found: Element properties, then Scope values.
If value for some variable was not found, then the result is filtered out.

*Exceptions*

None

*Modulation:*

* `by()` - Used to inject positional argument. For example:
`g.V().format("%{name} has %{_} connections").by(bothE().count())`.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/FormatStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#format-step[reference]

[[group-step]]
=== group()

*Description:* Groups objects in the traversal stream by a key and applies a reducing operation to the grouped values.

*Syntax:* `group()` | `group(String sideEffectKey)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`any`
|=========================================================

*Arguments:*

* `sideEffectKey` - The name of the side-effect key that will hold the aggregated grouping. When provided, the step
operates as a side-effect barrier step and passes the traverser to the next step unchanged. If `sideEffectKey` is
omitted, the step operates as a reducing barrier step, and a single traverser containing the computed map is passed to
the next step.

*Modulation:*

* `by()` - The first `by()` determines the key for grouping. The second `by()` determines the value to be reduced for
each group. If no key `by()` is provided, the object itself is used as the key. If no value `by()` is provided, the
objects are collected into a list.

*Considerations:*

The `group()` step can be used as both a reducing barrier step and a side-effect step. As a reducing barrier step (no
side-effect key), it returns a `Map<Object, Object>` where keys are the grouping criteria and values are the reduced
results. As a side-effect step, it stores the grouping in a side-effect and passes the traverser to the next step
unchanged. In both forms, this step is a barrier and must fully iterate the traversal before returning any results.

*Exceptions*

* If more than 2 `by()` modulators are provided, an `IllegalStateException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupSideEffectStep.java[source (sideEffect)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#group-step[reference]

[[groupcount-step]]
=== groupCount()

*Description:* Counts the number of times a particular object has been part of a traversal, returning a `Map` where the
object is the key and the value is the count.

*Syntax:* `groupCount()` | `groupCount(String sideEffectKey)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`any`
|=========================================================

*Arguments:*

* `sideEffectKey` - The name of the side-effect key that will hold the aggregated grouping. When provided, the step
operates as a side-effect step and passes the traverser to the next step unchanged.

*Modulation:*

* `by()` - Determines how to transform the object before counting. If not specified, the object itself is used as the
key.

*Considerations:*

The `groupCount()` step can be used as both a map step and a side-effect step. As a map step, it returns a
`Map<Object, Long>` with the counted objects as keys and their counts as values. As a side-effect step, it stores the
counts in a side-effect and passes the traverser to the next step unchanged. Note that both the map and side-effect
forms of this step are barriers that must fully iterate the traversal before returning any results.

*Exceptions*

* If multiple `by()` modulators are provided, an `IllegalStateException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/GroupCountStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/GroupCountSideEffectStep.java[source (sideEffect)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#groupcount-step[reference]

[[length-step]]
=== length()

*Description:* Returns the length of the incoming string or list, if `Scope.local` is specified, returns
the length of each string elements inside incoming list traverser.

*Syntax:* `length()` | `length(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`Integer`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LengthGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LengthLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#length-step[reference]

[[local-step]]
=== local()

*Description:* Executes the provided traversal in an object-local manner.

*Syntax:* `local(Traversal localTraversal)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`any` |`any`
|=========================================================

*Arguments:*

* `localTraversal` - The traversal that processes each single-object traverser individually.

*Modulation:*

None

*Considerations:*

The `local()` step enforces object-local execution. As a branching step with local children, it implements strict lazy
evaluation by passing a single traverser at a time to the local traversal (bulk of exactly one, if bulking is supported)
and resetting the traversal to clean state between executions.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LocalStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#local-step[reference]

[[intersect-step]]
=== intersect()

*Description:* Adds the intersection to the Traversal Stream.

*Syntax:* `intersect(Object values)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable` |`Set`
|=========================================================

*Arguments:*

* `values` - A list of items (as an Iterable or an array) or a `Traversal` that will produce a list of items.


*Modulation:*

None

*Considerations:*

A set is returned after the intersect operation is applied so there won't be duplicates. This step only applies to list
types which means that non-iterable types (including null) will cause exceptions to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IntersectStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#intersect-step[reference]

[[conjoin-step]]
=== conjoin()

*Description:* Joins every element in a list together into a String. 

*Syntax:* `conjoin(String delimiter)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable` |`String`
|=========================================================

*Arguments:*

* `delimiter` - A delimiter to use to join the elements together. Can't be null.

*Modulation:*

None

*Considerations:*

Every element in the list (except `null`) is converted to a String. Null values are ignored. The delimiter is inserted
between neighboring elements to form the final result. This step only applies to list types which means that
non-iterable types (including `null`) will cause exceptions to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConjoinStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#conjoin-step[reference]

[[lTrim-step]]
=== lTrim()

*Description:* Returns a string with leading whitespace removed.

*Syntax:* `lTrim()` | `lTrim(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`String`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LTrimLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#lTrim-step[reference]

[[merge-step]]
=== merge()

*Description:* Adds the union of two sets (or two maps) to the Traversal Stream.

*Syntax:* `merge(Object values)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable`/`Map` |`Set`/`Map`
|=========================================================

*Arguments:*

* `values` - A list of items (as an `Iterable` or an array), a `Map`, or a `Traversal` that will produce a list of items.

*Modulation:*

None

*Considerations:*

For iterable types, a set is returned after the merge operation is applied so there won't be duplicates. For maps, if
both maps contain the same key then the value yielded from the argument will be the value put into the merged map. This
step only applies to list types or maps which means that other non-iterable types (including null) will cause exceptions
to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) or map then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) or map then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#merge-step[reference]

[[merge-e-step]]
=== mergeE()

*Description:* Provides upsert-like functionality for edges.

*Syntax:* `mergeE()` | `mergeE(Map searchCreate)` | `mergeE(Traversal searchCreate)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|Y |Y |`option()` |`Map`/`Vertex` |`Edge`
|=========================================================

*Arguments:*

* `searchCreate` - A `Map` used to match an `Edge` and if not found will be the default set of data to create the new one.
* `onCreate` - A `Map` used to specify additional existence criteria and/or properties not already specified in `searchCreate`.
* `onMatch` - A `Map` used to update the `Edge` that is found using the `searchCreate` criteria.
* `outV` - A `Vertex` that will be late-bound into the `searchCreate` and `onCreate` `Maps` for the `Direction.OUT` key,
or else another `Map` used to search for that `Vertex`
* `inV` - A `Vertex` that will be late-bound into the `searchCreate` and `onCreate` `Maps` for the `Direction.IN` key,
or else another `Map` used to search for that `Vertex`

The `searchCreate` and `onCreate` `Map` instances must consist of any combination of:

* `T` - `id`, `label`
* `Direction` - `IN` or `to`, `OUT` or `from`
* Arbitrary `String` keys (which are assumed to be vertex properties).

The `onMatch` `Map` instance only allows for `String` keys as the `id` and `label` of a `Vertex` are immutable as are
the incident vertices. Values for these valid keys that are `null` will be treated according to the semantics of the
`addE()` step.

The `Map` that is used as the argument for `searchCreate` may be assigned from the incoming `Traverser` for the no-arg
`mergeE()`. If `mergeE(Map)` is used, then it will override the incoming `Traverser`. If `mergeE(Traversal)` is used,
the `Traversal` argument must resolve to a `Map` and it would also override the incoming Traverser. The `onCreate` and
`onMatch` arguments are assigned via modulation as described below.

If `onMatch` is triggered the `Traverser` becomes the matched `Edge`, but the traversal still must return a `Map`
instance to be applied. `Null` is considered semantically equivalent to an empty `Map`.

[width="100%",options="header"]
|=========================================================
|Event |Empty `Map` (or Null)
|Search |Matches all edges
|Create |New edge with defaults
|Update |No update to matched edge
|=========================================================

If `T.id` is used for `searchCreate` or `onCreate`, it may be ignored for edge creation if the `Graph` does not
support user supplied identifiers. `onCreate` inherits from `searchCreate` - values for `T.id`, `T.label`, and
`Direction.OUT/IN` do not need to be specified twice. Additionally, `onCreate` cannot override values in `searchCreate`
(i.e. `if (exists(x)) return(x) else create(y)` is not supported).

*Modulation:*

* `option(Merge, Map)` - Sets the `onCreate` or `onMatch` arguments directly.
* `option(Merge, Traversal)` - Sets the `onCreate` or `onMatch` arguments dynamically where the `Traversal` must
resolve to a `Map`.
* `option(Merge.outV/inV)` can also accept a `Traversal` that resolves to a `Vertex`, allowing `mergeE` to be combined
with `mergeV` via a `select` operation.

*Exceptions*

* `Map` arguments are validated for their keys resulting in exception if they do not meet requirements defined above.
* Use of `T.label` should always have a value that is a `String`.
* If `T.id`, `T.label`, and/or `Direction.IN/OUT` are specified in `searchCreate`, they cannot be overriden in `onCreate`.
* For late binding of the from and to vertices, `Direction.OUT` must be set to `Merge.outV` and `Direction.IN` must
be set to `Merge.inV`. Other combinations are not allowed and will result in exception.

*Considerations:*

* `mergeE()` (i.e. the zero-arg overload) can only be used mid-traversal. It is not a start step.
* As is common to Gremlin, it is expected that `Traversal` arguments may utilize `sideEffect()` steps.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeEdgeStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#mergee-step[reference]

[[merge-v-step]]
=== mergeV()

*Description:* Provides upsert-like functionality for vertices.

*Syntax:* `mergeV()` | `mergeV(Map searchCreate)` | `mergeV(Traversal searchCreate)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|Y |Y |`option()` |`Map` |`Vertex`
|=========================================================

*Arguments:*

* `searchCreate` - A `Map` used to match a `Vertex` and if not found will be the default set of data to create the new one.
* `onCreate` - A `Map` used to specify additional existence criteria and/or properties not already specified in `searchCreate`.
* `onMatch` - A `Map` used to update the `Vertex` that is found using the `searchCreate` criteria.

The `searchCreate` and `onCreate` `Map` instances must consists of any combination of `T.id`, `T.label`, or arbitrary
`String` keys (which are assumed to be vertex properties). The `onMatch` `Map` instance only allows for `String` keys
as the `id` and `label` of a `Vertex` are immutable. `null` Values for these valid keys are not allowed.

The `Map` that is used as the argument for `searchCreate` may be assigned from the incoming `Traverser` for the no-arg
`mergeV()`. If `mergeV(Map)` is used, then it will override the incoming `Traverser`. If `mergeV(Traversal)` is used,
the `Traversal` argument must resolve to a `Map` and it would also override the incoming Traverser. The `onCreate` and
`onMatch` arguments are assigned via modulation as described below.

If `onMatch` is triggered the `Traverser` becomes the matched `Vertex`, but the traversal still must return a `Map`
instance to be applied. `Null` is considered semantically equivalent to an empty `Map`.

[width="100%",options="header"]
|=========================================================
|Event |Empty `Map` (or Null)
|Search |Matches all vertices
|Create |New vertex with defaults
|Update |No update to matched vertex
|=========================================================

If `T.id` is used for `searchCreate` or `onCreate`, it may be ignored for vertex creation if the `Graph` does not
support user supplied identifiers. `onCreate` inherits from `searchCreate` - values for `T.id`, `T.label` do not need
to be specified twice. Additionally, `onCreate` cannot override values in `searchCreate`
(i.e. `if (exists(x)) return(x) else create(y)` is not supported).

*Modulation:*

* `option(Merge, Map)` - Sets the `onCreate` or `onMatch` arguments directly.
* `option(Merge, Traversal)` - Sets the `onCreate` or `onMatch` arguments dynamically where the `Traversal` must
resolve to a `Map`.

*Exceptions*

* `Map` arguments are validated for their keys resulting in exception if they do not meet requirements defined above.
* Use of `T.label` should always have a value that is a `String`.
* If `T.id` and/or `T.label` are specified in `searchCreate`, they cannot be overriden in `onCreate`.

*Considerations:*

* `mergeV()` (i.e. the zero-arg overload) can only be used mid-traversal. It is not a start step.
* As is common to Gremlin, it is expected that `Traversal` arguments may utilize `sideEffect()` steps.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MergeVertexStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#mergev-step[reference]

[[none-step]]
=== none()

*Description:* Filters array data from the traversal stream if none of the array's items match the supplied predicate.

*Syntax:* `none(P predicate)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`List`/`array`/`Iterable`/`Iterator` |`List`/`array`/`Iterable`/`Iterator`
|=========================================================

*Arguments:*

* `predicate` - The predicate used to test each value in the array data.

*Modulation:*

None

*Considerations:*

Each value will be tested using the supplied predicate. Empty lists always pass through and null/non-list traversers
will be filtered out of the traversal stream.

*Exceptions*

* A GremlinTypeErrorException will be thrown if one occurs and no other value evaluates to true.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/NoneStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#none-step[reference]


[[product-step]]
=== product()

*Description:* Adds the cartesian product to the Traversal Stream.

*Syntax:* `product(Object values)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`array`/`Iterable` |`List(List)`
|=========================================================

*Arguments:*

* `values` - A list of items (as an `Iterable` or an array) or a `Traversal` that will produce a list of items.

*Modulation:*

None

*Considerations:*

A list of lists is returned after the product operation is applied with the inner list being a result pair. This step only
applies to list types which means that non-iterable types (including null) will cause exceptions to be thrown.

*Exceptions*

* If the incoming traverser isn't a list (array or Iterable) then an `IllegalArgumentException` will be thrown.
* If the argument doesn't resolve to a list (array or Iterable) then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProductStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#product-step[reference]

[[project-step]]
=== project()

*Description:* Projects the current object in the stream into a `Map` that is keyed by the provided labels.

*Syntax:* `project(String projectKey, String... otherProjectKeys)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`Map<String, Object>`
|=========================================================

*Arguments:*

* `projectKey` - The first key to use in the resulting map.
* `otherProjectKeys` - Additional keys to use in the resulting map.

*Modulation:*

* `by()` - Determines how to transform the current object for each key in the resulting map. The number of `by()`
modulations should match the number of keys provided.

*Considerations:*

The `project()` step is similar to `select()` but instead of retrieving historic traverser state, it modulates the
current state of the traverser. Each key in the resulting map corresponds to a `by()` modulation in the order they are
provided. If a `by()` modulation doesn't produce a value for a particular key (not productive), that key will be omitted
from the resulting `Map`.

*Exceptions*

* If duplicate keys are provided, an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#project-step[reference]

[[repeat-step]]
=== repeat()

*Description:* Iteratively applies a traversal (the "loop body") to all incoming traversers until a stopping
condition is met. Optionally, it can emit traversers on each iteration according to an emit predicate. The
repeat step supports loop naming and a loop counter via `loops()`.

*Syntax:* `repeat(Traversal repeatTraversal)` | `repeat(String loopName, Traversal repeatTraversal)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`emit()`, `until()`, `times()` |`any` |`any`
|=========================================================

*Arguments:*

* `repeatTraversal` - The traversal that represents the loop body to apply on each iteration.
* `loopName` - Optional name used to identify the loop for nested loops and to access a specific counter via
`loops(loopName)`.

*Modulation:*

* `emit()` | `emit(Traversal<?, ?> emitTraversal)` | `emit(Predicate<Traverser<?>> emitPredicate)` - Controls if/when a
  traverser is emitted to the downstream of repeat() in addition to being looped again. If supplied before `repeat(...)`
  the predicate is evaluated prior to the first iteration (pre-emit). If supplied after `repeat(...)`, the predicate is
  evaluated after each completed iteration (post-emit). Calling `emit()` without arguments is equivalent to a predicate
  that always evaluates to true at the given check position.
* `until(Traversal<?, ?> untilTraversal)` | `until(Predicate<Traverser<?>> untilPredicate)` - Controls when repetition
  stops. If supplied before `repeat(...)` the predicate is evaluated prior to the first iteration (pre-check). If the
  predicate is true, the traverser will pass downstream without any loop iteration. If supplied after `repeat(...)`, the
  predicate is evaluated after each completed iteration (post-check). When the predicate is true, the traverser stops
  repeating and passes downstream.
* `times(int n)` - Convenience for a loop bound. Equivalent to `until(loops().is(n))` when placed after `repeat(...)`
  (post-check), and equivalent to `until(loops().is(n))` placed before `repeat(...)` (pre-check) when specified before.
  See Considerations for details and examples.

*Considerations:*

- Evaluation order matters. The placement of `emit()` and `until()` relative to `repeat()` controls whether their
predicates are evaluated before the first iteration (pre) or after each iteration (post) allowing for `while/do` or
`do/while` semantics respectively:
  - Pre-check / pre-emit: when the modulator appears before `repeat(...)`.
  - Post-check / post-emit: when the modulator appears after `repeat(...)`.
- Global traversal scope: The `repeatTraversal` is a global child. This means all traversers entering the repeat body
are processed together as a unified stream with global semantics. `Barrier` (`order()`, `sample()`, etc.) steps within
the repeat traversal operate across all traversers collectively rather than in isolation per traverser.
- Loop counter semantics:
  - The loop counter for a given named or unnamed repeat is incremented once per completion of the loop body (i.e.,
after the body finishes), not before. Therefore, `loops()` reflects the number of completed iterations.
  - `loops()` without arguments returns the counter for the closest (innermost) `repeat()`. `loops("name")` returns the
counter for the named loop.
- Re-queuing for the next iteration:
  - After each iteration, if `until` is not satisfied at the post-check, the traverser is sent back into the loop body
for another iteration. If it is satisfied, the traverser exits the loop and proceeds downstream.
- Interaction of `times(n)`:
  - `g.V().repeat(x).times(2)` applies `x` exactly twice; no values are emitted unless `emit()` is specified.
  - `g.V().emit().repeat(x).times(2)` emits the original input (pre-emit) and then the results of each iteration.
  - Placing `times(0)` before `repeat(...)` yields no iterations and passes the input downstream unchanged.
  - Placing `times(0)` after `repeat(...)` yields the same as `times(1)` because of `do/while` semantics.
- Errors when `repeatTraversal` is missing:
  - Using `emit()`, `until()`, or `times()` without an associated `repeat()` will raise an error at iteration time with a
message containing: `The repeat()-traversal was not defined`.
- Nested repeats and loop names:
  - Nested `repeat()` steps maintain separate loop counters. Use `repeat("a", ...)` and `loops("a")` to reference a
    specific counter inside nested loops.

*Exceptions*

* Using `emit()`, `until()`, or `times()` without a matching `repeat()` will raise an `IllegalStateException` at runtime
  when the step is initialized during iteration with the message containing: `The repeat()-traversal was not defined`.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/branch/RepeatStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#repeat-step[reference],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/branch/Repeat.feature[tests]

[[replace-step]]
=== replace()

*Description:* Returns a string with the specified characters in the original string replaced with the new characters.

*Syntax:* `replace(String oldChar, String newChar)` | `replace(Scope scope, String oldChar, String newChar)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`String`/`List`
|=========================================================

*Arguments:*

* `oldChar` - The string character(s) in the original string to be replaced. Nullable, a null input will be a no-op and
the original string will be returned
* `newChar` - The string character(s) to replace with. Nullable, a null input will be a no-op and the original string
will be returned
* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ReplaceGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ReplaceLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#replace-step[reference]

[[reverse-step]]
=== reverse()

*Description:* Returns the reverse of the incoming traverser

*Syntax:* `reverse()`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Object` |`Object`
|=========================================================

*Arguments:*

None

The behavior of reverse depends on the type of the incoming traverser. If the traverser is a string, then the string is
reversed. If the traverser is iterable (Iterable, Iterator, or an array) then a list containing the items in reverse
order are returned. All other types (including null) are not processed and are returned unmodified.

*Exceptions*

* If the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ReverseStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#reverse-step[reference]

[[rTrim-step]]
=== rTrim()

*Description:* Returns a string with trailing whitespace removed.

*Syntax:* `rTrim()` | `rTrim(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`String`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RTrimLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#rTrim-step[reference]

[[split-step]]
=== split()

*Description:* Returns a list of strings created by splitting the incoming string traverser around the matches of the given separator.

*Syntax:* `split(String separator)` | `split(Scope scope, String separator)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`List`
|=========================================================

*Arguments:*

* `separator` - The string character(s) used as delimiter to split the input string. Nullable, a null separator will split on
whitespaces. An empty string separator will split on each character.
* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SplitLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#split-step[reference]

[[subgraph-step]]
=== subgraph()

*Description:* Extracts an edge-induced subgraph from the current graph based on the edges encountered during traversal.

*Syntax:* `subgraph(String sideEffectKey)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`Edge` |`Edge`
|=========================================================

*Arguments:*

* `sideEffectKey` - The name of the side-effect key that will hold the extracted subgraph.

*Modulation:*

None

*Considerations:*

The `subgraph()` step is a side-effect step that extracts edges encountered during traversal and their incident vertices
into a new subgraph. The step passes traversers through unchanged while building the subgraph as a side-effect. Subgraph
step is a barrier and must fully iterate the traversal before returning any results.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/SubgraphStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#subgraph-step[reference]

[[substring-step]]
=== substring()

*Description:* Returns a substring of the incoming string traverser with a 0-based start index (inclusive) and end index (exclusive).

*Syntax:* `substring(int startIndex, int endIndex)` | `substring(Scope scope, int startIndex, int endIndex)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`String`/`List`
|=========================================================

*Arguments:*

* `startIndex` - The start index, 0 based. If the start index is negative then it will begin at the specified index counted
from the end of the string, or 0 if it exceeds the string length.
* `endIndex` - The end index, 0 based. Optional, if it is not specific then all remaining characters will be returned. End
index &leq; start index will return the empty string.
* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SubstringLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#substring-step[reference]

[[toLower-step]]
=== toLower()

*Description:* Returns the lowercase representation of incoming string traverser, or if `Scope.local` is specified, returns
the lowercase representation of each string elements inside incoming list traverser.

*Syntax:* `toLower()` | `toLower(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String` |`String`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ToLowerGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ToLowerLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#toLower-step[reference]

[[toUpper-step]]
=== toUpper()

*Description:* Returns the uppercase representation of incoming string traverser, or if `Scope.local` is specified, returns
the uppercase representation of each string elements inside incoming list traverser.

*Syntax:* `toUpper()` | `toUpper(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`String`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ToUpperGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ToUpperLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#toUpper-step[reference]

[[tree-step]]
=== tree()

*Description:* Aggregates the paths of the traversal into a tree data structure.

*Syntax:* `tree()` | `tree(String sideEffectKey)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()` |`any` |`any`
|=========================================================

*Arguments:*

* `sideEffectKey` - The name of the side-effect key that will hold the aggregated tree. When provided, the step
operates as a side-effect step and passes the traverser to the next step unchanged. If omitted, the step acts as a
reducing barrier step, and a single traverser containing the aggregated tree is passed to the next step.

*Modulation:*

* `by()` - Determines how to transform path objects before adding them to the tree. If not specified, the objects
themselves are used as tree nodes. If multiple `by()` modulators are provided, they will be applied to each level of the
tree according to a round robin. For example, if 2 `by()` modulators are present, the first `by()` will apply to the
first, third, fifth... levels of the tree, and the second `by()` will apply to the second, fourth, sixth... levels of
the tree. An unlimited number of `by()` modulators may be provided.

*Considerations:*

The `tree()` step can be used as both a map step and a side-effect step. As a map step, it returns a `Tree` data
structure representing the hierarchical paths taken during traversal. As a side-effect step, it stores the tree in a
side-effect and passes the traverser to the next step unchanged. The tree structure reflects the branching paths of the
traversal, with each level representing a step in the path.

*Exceptions*

None

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TreeStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/sideEffect/TreeSideEffectStep.java[source (sideEffect)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#tree-step[reference]

[[trim-step]]
=== trim()

*Description:* Returns a string with leading and trailing whitespace removed.

*Syntax:* `trim()` | `trim(Scope scope)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |N |`String`/`array`/`Iterable` |`String`/`List`
|=========================================================

*Arguments:*

* `scope` - Determines the type of traverser it operates on. Both scopes will operate on the level of individual traversers.
The `global` scope will operate on individual string traverser. The `local` scope will operate on list traverser with string elements inside.

Null values from the incoming traverser are not processed and remain as null when returned.

*Exceptions*

* For `Scope.global` or parameterless function calls, if the incoming traverser is a non-String value then an `IllegalArgumentException` will be thrown.
* For `Scope.local`, if the incoming traverser is not a string or a list of strings then an `IllegalArgumentException` will be thrown.

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimGlobalStep.java[source],
link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TrimLocalStep.java[source (local)],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#trim-step[reference]

[[valueMap-step]]
=== valueMap()

*Description:* Converts elements to a map representation of their properties.

*Syntax:* `valueMap(String... propertyKeys)` | `valueMap(boolean includeTokens, String... propertyKeys)`

[width="100%",options="header"]
|=========================================================
|Start Step |Mid Step |Modulated |Domain |Range
|N |Y |`by()`/`with()` |`Element` |`Map`
|=========================================================

*Arguments:*

* `includeTokens` - Determines if the result map should contain entries from `T` (such as `label` and `id`).

* `propertyKeys` - If `valueMap()` is provided a list of propertyKeys, then the result map will only contain entries
specified by propertyKeys. If the list is empty, then all properties are included.

*Modulation:*

* `by(Traversal)` - Only a single by() modulator is allowed and it applies to all map values. An attempt to add more
than one by() will result in an Exception that contains the message "valueMap()/propertyMap() step can only have one by
modulator".
* `with(key, value)` - Determines which optional entries to add to the map. The key is "tinkerpop.valueMap.tokens" and
the possible values are:
** 0 for no tokens
** 1 for including id (Element)
** 2 for including label (Vertex/Edge)
** 4 for including keys (VertexProperty)
** 8 for including values (VertexProperty)
** 15 for including all

See: link:https://github.com/apache/tinkerpop/tree/x.y.z/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java[source],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#valuemap-step[reference],
link:https://tinkerpop.apache.org/docs/x.y.z/reference/#propertymap-step[reference]
