This is an automated email from the ASF dual-hosted git repository.

spmallette pushed a commit to branch TINKERPOP-2235
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git

commit 4ef74c3aa17bac2b18006ee3144e16eee833fb9c
Author: stephen <[email protected]>
AuthorDate: Tue Nov 19 13:20:15 2019 -0500

    TINKERPOP-2235 Major refactoring and introduction of ScalarMapStep
    
    ScalarMapStep extends and replaces MapStep as the "easy" way to implement a 
new MapStep. ScalarMapStep works nicely when you don't have to fuss with null 
logic and is still appropriate for use in those cases where a step will not 
produce a null value (e.g. addV()). For all other cases, you basically have to 
extend MapStep directly and implement processNextStart() by hand.
---
 CHANGELOG.asciidoc                                 |  1 +
 docs/src/upgrade/release-3.5.x.asciidoc            | 40 ++++++++++++++++
 .../traversal/step/filter/WhereTraversalStep.java  |  4 +-
 .../process/traversal/step/map/AddEdgeStep.java    |  2 +-
 .../process/traversal/step/map/AddVertexStep.java  |  2 +-
 .../process/traversal/step/map/ConstantStep.java   |  2 +-
 .../process/traversal/step/map/CountLocalStep.java |  2 +-
 .../process/traversal/step/map/DedupLocalStep.java |  2 +-
 .../traversal/step/map/EdgeOtherVertexStep.java    |  2 +-
 .../process/traversal/step/map/ElementMapStep.java |  2 +-
 .../gremlin/process/traversal/step/map/IdStep.java |  2 +-
 .../process/traversal/step/map/IndexStep.java      |  2 +-
 .../process/traversal/step/map/LabelStep.java      |  2 +-
 .../process/traversal/step/map/LambdaMapStep.java  |  2 +-
 .../process/traversal/step/map/LoopsStep.java      |  2 +-
 .../process/traversal/step/map/MapStep.java        | 27 ++---------
 .../process/traversal/step/map/MathStep.java       |  2 +-
 .../process/traversal/step/map/MaxLocalStep.java   |  2 +-
 .../process/traversal/step/map/MeanLocalStep.java  |  2 +-
 .../process/traversal/step/map/MinLocalStep.java   |  2 +-
 .../process/traversal/step/map/OrderLocalStep.java |  2 +-
 .../process/traversal/step/map/PathStep.java       |  2 +-
 .../process/traversal/step/map/ProjectStep.java    |  2 +-
 .../traversal/step/map/PropertyKeyStep.java        |  2 +-
 .../traversal/step/map/PropertyMapStep.java        |  2 +-
 .../traversal/step/map/PropertyValueStep.java      |  2 +-
 .../process/traversal/step/map/RangeLocalStep.java |  2 +-
 .../process/traversal/step/map/SackStep.java       |  2 +-
 .../traversal/step/map/SampleLocalStep.java        |  2 +-
 .../{PropertyKeyStep.java => ScalarMapStep.java}   | 25 +++++-----
 .../process/traversal/step/map/SelectOneStep.java  | 54 +++++++++++++++-------
 .../process/traversal/step/map/SelectStep.java     | 20 +++-----
 .../process/traversal/step/map/SumLocalStep.java   |  2 +-
 .../process/traversal/step/map/TailLocalStep.java  |  2 +-
 .../traversal/step/map/TraversalMapStep.java       | 12 ++---
 .../traversal/step/map/TraversalSelectStep.java    | 41 ++++++++--------
 .../finalization/ReferenceElementStrategy.java     |  4 +-
 gremlin-test/features/map/Map.feature              | 16 +++++++
 .../process/traversal/step/map/MapTest.java        | 22 +++++++++
 .../strategy/decoration/OptionsStrategyTest.java   |  4 +-
 40 files changed, 198 insertions(+), 126 deletions(-)

diff --git a/CHANGELOG.asciidoc b/CHANGELOG.asciidoc
index 58dc701..b88d717 100644
--- a/CHANGELOG.asciidoc
+++ b/CHANGELOG.asciidoc
@@ -27,6 +27,7 @@ This release also includes changes from <<release-3-4-3, 
3.4.3>>.
 
 * Allowed the possibility for the user of `null` in Gremlin.
 * Added a `Graph.Feature` for `supportsNullPropertyValues`.
+* Refactored `MapStep` to move its logic to `ScalarMapStep` so that the old 
behavior could be preserved while allow other implementations to have more 
flexibility.
 * Modified TinkerGraph to support `null` property values and can be configured 
to disable that feature.
 * Modified `null` handling in mutations to be consistent for a new `Vertex` as 
well as update to an existing one.
 * Upgraded to Apache Commons Configuration2.
diff --git a/docs/src/upgrade/release-3.5.x.asciidoc 
b/docs/src/upgrade/release-3.5.x.asciidoc
index f0739e5..cdd920b 100644
--- a/docs/src/upgrade/release-3.5.x.asciidoc
+++ b/docs/src/upgrade/release-3.5.x.asciidoc
@@ -257,6 +257,46 @@ 
link:http://tinkerpop.apache.org/docs/3.5.0/upgrade/#_ssl_security[3.2.10 Upgrad
 
 ==== Graph System Providers
 
+===== ScalarMapStep
+
+`MapStep` had a single abstract method that needed to be implemented:
+
+[source,java]
+----
+protected abstract E map(final Traverser.Admin<S> traverser);
+----
+
+This method made it easy to implement new implementations because it hid 
certain processing logic and made it so that
+the implementer only had to reason about how to take the current object from 
the `Traverser` and transform it to a
+new value. As 3.5.0 changed semantics around how `null` is processed, this 
method became a bit of a hindrance to the
+more complex logic which those semantics entailed. Specifically, this method 
could not easily communicate to underlying
+processing what a `null` might mean - is the `null` the end of the traversal 
stream or should the `null` be promoted
+down the stream as a value to be processed.
+
+Interestingly, the method that enabled the handling of this more complex 
decision making already existed in
+`AbstractStep`:
+
+[source,java]
+----
+protected Traverser.Admin<E> processNextStart()
+----
+
+It returns a whole `Traverser` object and forces manual retrieval of the 
"next" `Traverser`. At this level it becomes
+possible to make choices on `null` and return it if it should be propagated or 
dismiss it and return an
+`EmptyTraverser`. To better accommodate the `MapStep` which provides the nice 
helper `map(Traverser)` method as well
+as the more flexible version that doesn't need that infrastructure, 
`ScalarMapStep` was added to extend `MapStep`. The
+`map(Traverser)` was then moved to `ScalarMapStep` and those steps that could 
rely on that helper method now extend
+from it. All other steps of this sort still extend `MapStep` and directly 
implement `processNextStart()`.
+
+Providers will get compile errors if they extended `MapStep`. The easy 
solution will be to simply modify that code so
+that their step instead extends `ScalarMapStep`. As a secondary task, 
providers should then examine their step
+implementation to ensure that `null` semantics as presented in 3.5.0 apply 
properly. If they do not, then it is likely
+that the step should simply implement `MapStep` directly and former 
`map(Traverser)` logic should be migrated to
+`processNextStart()`.
+
+See: link:https://issues.apache.org/jira/browse/TINKERPOP-2235[TINKERPOP-2235],
+link:https://issues.apache.org/jira/browse/TINKERPOP-2099[TINKERPOP-2099]
+
 ===== TraversalStrategy Application
 
 The methodology for strategy application has been altered and the change is 
most easily described by example. Given a
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
index 384bbce..8c701a9 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/filter/WhereTraversalStep.java
@@ -25,7 +25,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.StartStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.ProfileStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.ConnectiveStrategy;
@@ -149,7 +149,7 @@ public final class WhereTraversalStep<S> extends 
FilterStep<S> implements Traver
 
     //////////////////////////////
 
-    public static class WhereStartStep<S> extends MapStep<S, Object> 
implements Scoping {
+    public static class WhereStartStep<S> extends ScalarMapStep<S, Object> 
implements Scoping {
 
         private String selectKey;
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
index aa3818b..b8d7d35 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddEdgeStep.java
@@ -45,7 +45,7 @@ import java.util.Set;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public class AddEdgeStep<S> extends MapStep<S, Edge>
+public class AddEdgeStep<S> extends ScalarMapStep<S, Edge>
         implements Mutating<Event.EdgeAddedEvent>, TraversalParent, Scoping, 
FromToModulating {
 
     private static final String FROM = Graph.Hidden.hide("from");
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
index 4961025..296e8b5 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/AddVertexStep.java
@@ -40,7 +40,7 @@ import java.util.Set;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public class AddVertexStep<S> extends MapStep<S, Vertex>
+public class AddVertexStep<S> extends ScalarMapStep<S, Vertex>
         implements Mutating<Event.VertexAddedEvent>, TraversalParent, Scoping {
 
     private Parameters parameters = new Parameters();
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
index 749de31..9434cc3 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ConstantStep.java
@@ -27,7 +27,7 @@ import java.util.Collections;
 import java.util.Objects;
 import java.util.Set;
 
-public class ConstantStep<S, E> extends MapStep<S, E> {
+public class ConstantStep<S, E> extends ScalarMapStep<S, E> {
 
     private final E constant;
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
index 87b699d..25e75e4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/CountLocalStep.java
@@ -32,7 +32,7 @@ import java.util.Set;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class CountLocalStep<S> extends MapStep<S, Long> {
+public final class CountLocalStep<S> extends ScalarMapStep<S, Long> {
 
     public CountLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
index 59c66c7..4d75270 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/DedupLocalStep.java
@@ -29,7 +29,7 @@ import java.util.Set;
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class DedupLocalStep<E, S extends Iterable<E>> extends MapStep<S, 
Set<E>> {
+public final class DedupLocalStep<E, S extends Iterable<E>> extends 
ScalarMapStep<S, Set<E>> {
 
     public DedupLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
index a53dd50..0d151d0 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/EdgeOtherVertexStep.java
@@ -34,7 +34,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public class EdgeOtherVertexStep extends MapStep<Edge, Vertex> implements 
Configuring {
+public class EdgeOtherVertexStep extends ScalarMapStep<Edge, Vertex> 
implements Configuring {
     protected Parameters parameters = new Parameters();
 
     public EdgeOtherVertexStep(final Traversal.Admin traversal) {
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
index 2f1db43..1654aa1 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ElementMapStep.java
@@ -45,7 +45,7 @@ import java.util.Set;
  * @author Daniel Kuppitz (http://gremlin.guru)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public class ElementMapStep<K,E> extends MapStep<Element, Map<K, E>> 
implements TraversalParent, GraphComputing {
+public class ElementMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>> 
implements TraversalParent, GraphComputing {
 
     protected final String[] propertyKeys;
     private boolean onGraphComputer = false;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
index 018c91e..c5eb7c4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IdStep.java
@@ -29,7 +29,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class IdStep<S extends Element> extends MapStep<S, Object> {
+public final class IdStep<S extends Element> extends ScalarMapStep<S, Object> {
 
     public IdStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
index b903c15..314e751 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/IndexStep.java
@@ -40,7 +40,7 @@ import java.util.function.Function;
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public class IndexStep<S, E> extends MapStep<S, E> implements TraversalParent, 
Configuring {
+public class IndexStep<S, E> extends ScalarMapStep<S, E> implements 
TraversalParent, Configuring {
 
     private final static IllegalArgumentException 
INVALID_CONFIGURATION_EXCEPTION =
             new IllegalArgumentException("WithOptions.indexer requires a 
single Integer argument (possible " + "" +
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
index 2b2313f..060dc68 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LabelStep.java
@@ -29,7 +29,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class LabelStep<S extends Element> extends MapStep<S, String> {
+public final class LabelStep<S extends Element> extends ScalarMapStep<S, 
String> {
 
     public LabelStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
index b2024f8..ce6a1bd 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LambdaMapStep.java
@@ -28,7 +28,7 @@ import java.util.function.Function;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class LambdaMapStep<S, E> extends MapStep<S, E> implements 
LambdaHolder {
+public final class LambdaMapStep<S, E> extends ScalarMapStep<S, E> implements 
LambdaHolder {
 
     private final Function<Traverser<S>, E> function;
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
index 11d8729..c3d2ac8 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/LoopsStep.java
@@ -24,7 +24,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class LoopsStep<S> extends MapStep<S, Integer> {
+public final class LoopsStep<S> extends ScalarMapStep<S, Integer> {
 
     private String loopName;
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
index 51535e7..5d5103c 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapStep.java
@@ -18,12 +18,16 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Step;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.AbstractStep;
-import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 
 /**
+ * A marker base class that designates an extending {@link Step} as a "Map" 
step which will transform the object of one
+ * {@link Traverser} into another. In many cases, it may be easier to simply 
extend from {@link ScalarMapStep} which
+ * has a straightforward implementation pattern.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Stephen Mallette (http://stephen.genoprime.com)
  */
@@ -32,26 +36,5 @@ public abstract class MapStep<S, E> extends AbstractStep<S, 
E> {
     public MapStep(final Traversal.Admin traversal) {
         super(traversal);
     }
-
-    @Override
-    protected Traverser.Admin<E> processNextStart() {
-        final Traverser.Admin<S> traverser = this.starts.next();
-        final E obj = this.map(traverser);
-        return isEmptyTraverser(obj) ? EmptyTraverser.instance() : 
traverser.split(obj, this);
-    }
-
-    protected abstract E map(final Traverser.Admin<S> traverser);
-
-    /**
-     * Determines if the value returned from {@link #map(Traverser.Admin)} 
should be representative of an
-     * {@link EmptyTraverser}. Such traversers will effectively be filtered 
out by the traversal. This method works in
-     * conjunction with {@link #map(Traverser.Admin)} in the sense that both 
work are called in the default
-     * implementation of {@link #processNextStart()} which will call this 
method after "map()"-ing the traverser to
-     * determine if that step consider the returned value as "empty".
-     */
-    protected boolean isEmptyTraverser(final E obj) {
-        return false;
-    }
-
 }
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
index 0994411..b463833 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MathStep.java
@@ -44,7 +44,7 @@ import java.util.regex.Pattern;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class MathStep<S> extends MapStep<S, Double> implements 
ByModulating, TraversalParent, Scoping, PathProcessor {
+public final class MathStep<S> extends ScalarMapStep<S, Double> implements 
ByModulating, TraversalParent, Scoping, PathProcessor {
 
     private static final String CURRENT = "_";
     private final String equation;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
index 3ad326f..187ad39 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MaxLocalStep.java
@@ -33,7 +33,7 @@ import static 
org.apache.tinkerpop.gremlin.util.NumberHelper.max;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> 
extends MapStep<S, E> {
+public final class MaxLocalStep<E extends Comparable, S extends Iterable<E>> 
extends ScalarMapStep<S, E> {
 
     public MaxLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
index 91447fd..5ffb1a6 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MeanLocalStep.java
@@ -32,7 +32,7 @@ import java.util.Set;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MeanLocalStep<E extends Number, S extends Iterable<E>> 
extends MapStep<S, Number> {
+public final class MeanLocalStep<E extends Number, S extends Iterable<E>> 
extends ScalarMapStep<S, Number> {
 
     public MeanLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
index 4139a7d..3bdb969 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MinLocalStep.java
@@ -33,7 +33,7 @@ import static 
org.apache.tinkerpop.gremlin.util.NumberHelper.min;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> 
extends MapStep<S, E> {
+public final class MinLocalStep<E extends Comparable, S extends Iterable<E>> 
extends ScalarMapStep<S, E> {
 
     public MinLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
index 95cb6db..97a68ff 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/OrderLocalStep.java
@@ -43,7 +43,7 @@ import java.util.stream.Collectors;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class OrderLocalStep<S, C extends Comparable> extends MapStep<S, 
S> implements ComparatorHolder<S, C>, ByModulating, TraversalParent {
+public final class OrderLocalStep<S, C extends Comparable> extends 
ScalarMapStep<S, S> implements ComparatorHolder<S, C>, ByModulating, 
TraversalParent {
 
     private List<Pair<Traversal.Admin<S, C>, Comparator<C>>> comparators = new 
ArrayList<>();
     private ChainedComparator<S, C> chainedComparator = null;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
index b49a1e4..82f19b4 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PathStep.java
@@ -38,7 +38,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PathStep<S> extends MapStep<S, Path> implements 
TraversalParent, PathProcessor, ByModulating, FromToModulating {
+public final class PathStep<S> extends ScalarMapStep<S, Path> implements 
TraversalParent, PathProcessor, ByModulating, FromToModulating {
 
     private TraversalRing<Object, Object> traversalRing;
     private Set<String> keepLabels;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
index 3ddd4a6..66c63e0 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ProjectStep.java
@@ -37,7 +37,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class ProjectStep<S, E> extends MapStep<S, Map<String, E>> 
implements TraversalParent, ByModulating {
+public final class ProjectStep<S, E> extends ScalarMapStep<S, Map<String, E>> 
implements TraversalParent, ByModulating {
 
     private final List<String> projectKeys;
     private TraversalRing<S, E> traversalRing;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
index ea1db27..9e7a0ab 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
@@ -29,7 +29,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PropertyKeyStep extends MapStep<Property, String> {
+public final class PropertyKeyStep extends ScalarMapStep<Property, String> {
 
     public PropertyKeyStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
index a58aaaf..ecc82f9 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyMapStep.java
@@ -49,7 +49,7 @@ import java.util.Set;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public class PropertyMapStep<K,E> extends MapStep<Element, Map<K, E>>
+public class PropertyMapStep<K,E> extends ScalarMapStep<Element, Map<K, E>>
         implements TraversalParent, ByModulating, Configuring {
 
     protected final String[] propertyKeys;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
index eab0ea6..6f41010 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyValueStep.java
@@ -29,7 +29,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class PropertyValueStep<E> extends MapStep<Property<E>, E> {
+public final class PropertyValueStep<E> extends ScalarMapStep<Property<E>, E> {
 
     public PropertyValueStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
index 905a80c..f72a0cb 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/RangeLocalStep.java
@@ -36,7 +36,7 @@ import java.util.Set;
 /**
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class RangeLocalStep<S> extends MapStep<S, S> {
+public final class RangeLocalStep<S> extends ScalarMapStep<S, S> {
 
     private final long low;
     private final long high;
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
index 3e0385b..7f12a00 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SackStep.java
@@ -28,7 +28,7 @@ import java.util.Set;
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class SackStep<S, E> extends MapStep<S, E> {
+public final class SackStep<S, E> extends ScalarMapStep<S, E> {
 
     public SackStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
index 5f83c53..ef65202 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SampleLocalStep.java
@@ -36,7 +36,7 @@ import java.util.Set;
  * @author Daniel Kuppitz (http://gremlin.guru)
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  */
-public final class SampleLocalStep<S> extends MapStep<S, S> {
+public final class SampleLocalStep<S> extends ScalarMapStep<S, S> {
 
     private static final Random RANDOM = new Random();
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java
similarity index 60%
copy from 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
copy to 
gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java
index ea1db27..78e0766 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/PropertyKeyStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/ScalarMapStep.java
@@ -20,28 +20,25 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
-import org.apache.tinkerpop.gremlin.structure.Property;
-
-import java.util.Collections;
-import java.util.Set;
 
 /**
+ * A type of {@link MapStep} class which will transform the object of one 
{@link Traverser} into another. This class
+ * simply requires the implementation of the {@link #map(Traverser.Admin)} 
method to extract the object of the given
+ * {@link Traverser} and return the transformation of that object as {@code E}.
+ *
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
-public final class PropertyKeyStep extends MapStep<Property, String> {
-
-    public PropertyKeyStep(final Traversal.Admin traversal) {
+public abstract class ScalarMapStep<S, E> extends MapStep<S,E> {
+    public ScalarMapStep(final Traversal.Admin traversal) {
         super(traversal);
     }
 
     @Override
-    protected String map(final Traverser.Admin<Property> traverser) {
-        return traverser.get().key();
+    protected Traverser.Admin<E> processNextStart() {
+        final Traverser.Admin<S> traverser = this.starts.next();
+        return traverser.split(this.map(traverser), this);
     }
 
-    @Override
-    public Set<TraverserRequirement> getRequirements() {
-        return Collections.singleton(TraverserRequirement.OBJECT);
-    }
+    protected abstract E map(final Traverser.Admin<S> traverser);
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
index a87f9ef..44e22fe 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectOneStep.java
@@ -18,6 +18,7 @@
  */
 package org.apache.tinkerpop.gremlin.process.traversal.step.map;
 
+import org.apache.tinkerpop.gremlin.process.traversal.Path;
 import org.apache.tinkerpop.gremlin.process.traversal.Pop;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
@@ -26,12 +27,16 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
 import org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
@@ -39,7 +44,6 @@ import java.util.Set;
  */
 public final class SelectOneStep<S, E> extends MapStep<S, E> implements 
TraversalParent, Scoping, PathProcessor, ByModulating {
 
-    private static final Object NOTHING_SELECTED = new Object();
     private final Pop pop;
     private final String selectKey;
     private Traversal.Admin<S, E> selectTraversal = null;
@@ -52,15 +56,39 @@ public final class SelectOneStep<S, E> extends MapStep<S, 
E> implements Traversa
     }
 
     @Override
-    protected E map(final Traverser.Admin<S> traverser) {
-        final E end = this.getScopeValue(this.pop, this.selectKey, traverser, 
(E) NOTHING_SELECTED);
-        if (NOTHING_SELECTED == end) return end;
-        return null != end ? TraversalUtil.applyNullable((S) end, 
this.selectTraversal) : null;
-    }
+    protected Traverser.Admin<E> processNextStart() throws 
NoSuchElementException {
+        final Traverser.Admin<S> traverser = this.starts.next();
+
+        final Object object = traverser.get();
+        if (object instanceof Map && ((Map<String, S>) 
object).containsKey(this.selectKey)) {
+            final S o = ((Map<String, S>) object).get(this.selectKey);
+            if (null == o) return traverser.split(null, this);
+            final Traverser.Admin<E> outTraverser = 
traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this);
+            if (!(this.getTraversal().getParent() instanceof MatchStep))
+                PathProcessor.processTraverserPathLabels(outTraverser, 
this.keepLabels);
+            return outTraverser;
+        }
 
-    @Override
-    protected boolean isEmptyTraverser(final E obj) {
-        return NOTHING_SELECTED == obj;
+        if (traverser.getSideEffects().exists(this.selectKey)) {
+            final S o = (S) traverser.getSideEffects().get(this.selectKey);
+            if (null == o) return traverser.split(null, this);
+            final Traverser.Admin<E> outTraverser = 
traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this);
+            if (!(this.getTraversal().getParent() instanceof MatchStep))
+                PathProcessor.processTraverserPathLabels(outTraverser, 
this.keepLabels);
+            return outTraverser;
+        }
+
+        final Path path = traverser.path();
+        if (path.hasLabel(this.selectKey)) {
+            final S o = (S) path.get(pop, this.selectKey);
+            if (null == o) return traverser.split(null, this);
+            final Traverser.Admin<E> outTraverser = 
traverser.split(TraversalUtil.applyNullable(o, this.selectTraversal), this);
+            if (!(this.getTraversal().getParent() instanceof MatchStep))
+                PathProcessor.processTraverserPathLabels(outTraverser, 
this.keepLabels);
+            return outTraverser;
+        }
+
+        return EmptyTraverser.instance();
     }
 
     @Override
@@ -132,14 +160,6 @@ public final class SelectOneStep<S, E> extends MapStep<S, 
E> implements Traversa
         return this.keepLabels;
     }
 
-    @Override
-    protected Traverser.Admin<E> processNextStart() {
-        final Traverser.Admin<E> traverser = super.processNextStart();
-        if (!(this.getTraversal().getParent() instanceof MatchStep)) {
-            PathProcessor.processTraverserPathLabels(traverser, 
this.keepLabels);
-        }
-        return traverser;
-    }
 }
 
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
index db15a28..2fa3e1f 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SelectStep.java
@@ -27,7 +27,6 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.Scoping;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
-import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalHelper;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalRing;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
@@ -39,10 +38,12 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public final class SelectStep<S, E> extends MapStep<S, Map<String, E>> 
implements Scoping, TraversalParent, PathProcessor, ByModulating {
 
@@ -62,7 +63,8 @@ public final class SelectStep<S, E> extends MapStep<S, 
Map<String, E>> implement
     }
 
     @Override
-    protected Map<String, E> map(final Traverser.Admin<S> traverser) {
+    protected Traverser.Admin<Map<String, E>> processNextStart() throws 
NoSuchElementException {
+        final Traverser.Admin<S> traverser = this.starts.next();
         final Map<String, E> bindings = new 
LinkedHashMap<>(this.selectKeys.size(), 1.0f);
         for (final String selectKey : this.selectKeys) {
             final E end = this.getNullableScopeValue(this.pop, selectKey, 
traverser);
@@ -70,16 +72,11 @@ public final class SelectStep<S, E> extends MapStep<S, 
Map<String, E>> implement
                 bindings.put(selectKey, TraversalUtil.applyNullable(end, 
this.traversalRing.next()));
             else {
                 this.traversalRing.reset();
-                return null;
+                return EmptyTraverser.instance();
             }
         }
         this.traversalRing.reset();
-        return bindings;
-    }
-
-    @Override
-    protected boolean isEmptyTraverser(final Map<String, E> obj) {
-        return null == obj;
+        return 
PathProcessor.processTraverserPathLabels(traverser.split(bindings, this), 
this.keepLabels);
     }
 
     @Override
@@ -156,9 +153,4 @@ public final class SelectStep<S, E> extends MapStep<S, 
Map<String, E>> implement
     public Set<String> getKeepLabels() {
         return this.keepLabels;
     }
-
-    @Override
-    protected Traverser.Admin<Map<String, E>> processNextStart() {
-        return 
PathProcessor.processTraverserPathLabels(super.processNextStart(), 
this.keepLabels);
-    }
 }
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
index 72e6539..3249e31 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/SumLocalStep.java
@@ -32,7 +32,7 @@ import java.util.Set;
  * @author Marko A. Rodriguez (http://markorodriguez.com)
  * @author Daniel Kuppitz (http://gremlin.guru)
  */
-public final class SumLocalStep<E extends Number, S extends Iterable<E>> 
extends MapStep<S, E> {
+public final class SumLocalStep<E extends Number, S extends Iterable<E>> 
extends ScalarMapStep<S, E> {
 
     public SumLocalStep(final Traversal.Admin traversal) {
         super(traversal);
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
index ea678a5..336323e 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TailLocalStep.java
@@ -34,7 +34,7 @@ import java.util.Set;
 /**
  * @author Matt Frantz (http://github.com/mhfrantz)
  */
-public final class TailLocalStep<S> extends MapStep<S, S> {
+public final class TailLocalStep<S> extends ScalarMapStep<S, S> {
 
     private final long limit;
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
index 32c2e3c..7dc82d7 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalMapStep.java
@@ -29,10 +29,12 @@ import 
org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.Set;
 
 /**
  * @author Marko A. Rodriguez (http://markorodriguez.com)
+ * @author Stephen Mallette (http://stephen.genoprime.com)
  */
 public final class TraversalMapStep<S, E> extends MapStep<S, E> implements 
TraversalParent {
 
@@ -44,14 +46,10 @@ public final class TraversalMapStep<S, E> extends 
MapStep<S, E> implements Trave
     }
 
     @Override
-    protected E map(final Traverser.Admin<S> traverser) {
+    protected Traverser.Admin<E> processNextStart() throws 
NoSuchElementException {
+        final Traverser.Admin<S> traverser = this.starts.next();
         final Iterator<E> iterator = TraversalUtil.applyAll(traverser, 
this.mapTraversal);
-        return iterator.hasNext() ? iterator.next() : null;
-    }
-
-    @Override
-    protected boolean isEmptyTraverser(final E obj) {
-        return null == obj;
+        return  iterator.hasNext() ? traverser.split(iterator.next(), this) : 
EmptyTraverser.instance();
     }
 
     @Override
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
index 71ac06c..b1b1263 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/TraversalSelectStep.java
@@ -26,6 +26,7 @@ import 
org.apache.tinkerpop.gremlin.process.traversal.step.ByModulating;
 import org.apache.tinkerpop.gremlin.process.traversal.step.PathProcessor;
 import org.apache.tinkerpop.gremlin.process.traversal.step.TraversalParent;
 import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.TraverserRequirement;
+import 
org.apache.tinkerpop.gremlin.process.traversal.traverser.util.EmptyTraverser;
 import org.apache.tinkerpop.gremlin.process.traversal.util.TraversalUtil;
 import org.apache.tinkerpop.gremlin.structure.util.StringFactory;
 
@@ -54,26 +55,42 @@ public final class TraversalSelectStep<S, E> extends 
MapStep<S, E> implements Tr
     }
 
     @Override
-    protected E map(final Traverser.Admin<S> traverser) {
+    protected Traverser.Admin<E> processNextStart() {
+        final Traverser.Admin<S> traverser = this.starts.next();
+
+        boolean found = false;
         E end = null;
         final Iterator<E> keyIterator = TraversalUtil.applyAll(traverser, 
this.keyTraversal);
         if (keyIterator.hasNext()) {
             final E key = keyIterator.next();
             final Object object = traverser.get();
-            if (object instanceof Map && ((Map) object).containsKey(key))
+            if (object instanceof Map && ((Map) object).containsKey(key)) {
                 end = (E) ((Map) object).get(key);
-            else if (key instanceof String) {
+                found = true;
+            } else if (key instanceof String) {
                 final String skey = (String) key;
                 if (traverser.getSideEffects().exists(skey)) {
                     end = traverser.getSideEffects().get((String) key);
+                    found = true;
                 } else {
                     final Path path = traverser.path();
-                    if (path.hasLabel(skey))
+                    if (path.hasLabel(skey)) {
                         end = null == pop ? path.get(skey) : path.get(pop, 
skey);
+                        found = true;
+                    }
                 }
             }
         }
-        return null != end ? TraversalUtil.applyNullable(end, 
this.selectTraversal) : null;
+
+        if (found) {
+            final Traverser.Admin<E> outTraverser = traverser.split(null == 
end ? null : TraversalUtil.applyNullable(end, this.selectTraversal), this);
+            if (!(this.getTraversal().getParent() instanceof MatchStep)) {
+                PathProcessor.processTraverserPathLabels(outTraverser, 
this.keepLabels);
+            }
+            return outTraverser;
+        } else {
+            return EmptyTraverser.instance();
+        }
     }
 
     @Override
@@ -130,11 +147,6 @@ public final class TraversalSelectStep<S, E> extends 
MapStep<S, E> implements Tr
                 TraverserRequirement.PATH);
     }
 
-    //@Override
-    //public Set<String> getScopeKeys() {
-    //    return Collections.singleton(this.selectKey);
-    //}
-
     public Pop getPop() {
         return this.pop;
     }
@@ -148,15 +160,6 @@ public final class TraversalSelectStep<S, E> extends 
MapStep<S, E> implements Tr
     public Set<String> getKeepLabels() {
         return this.keepLabels;
     }
-
-    @Override
-    protected Traverser.Admin<E> processNextStart() {
-        final Traverser.Admin<E> traverser = super.processNextStart();
-        if (!(this.getTraversal().getParent() instanceof MatchStep)) {
-            PathProcessor.processTraverserPathLabels(traverser, 
this.keepLabels);
-        }
-        return traverser;
-    }
 }
 
 
diff --git 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
index 41e1325..ebb0423 100644
--- 
a/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
+++ 
b/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ReferenceElementStrategy.java
@@ -21,7 +21,7 @@ package 
org.apache.tinkerpop.gremlin.process.traversal.strategy.finalization;
 import org.apache.tinkerpop.gremlin.process.traversal.Traversal;
 import org.apache.tinkerpop.gremlin.process.traversal.TraversalStrategy;
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.step.sideEffect.ProfileSideEffectStep;
 import org.apache.tinkerpop.gremlin.process.traversal.step.util.EmptyStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.AbstractTraversalStrategy;
@@ -56,7 +56,7 @@ public final class ReferenceElementStrategy extends 
AbstractTraversalStrategy<Tr
         return INSTANCE;
     }
 
-    public static class ReferenceElementStep<S, E> extends MapStep<S, E> {
+    public static class ReferenceElementStep<S, E> extends ScalarMapStep<S, E> 
{
 
         public ReferenceElementStep(final Traversal.Admin traversal) {
             super(traversal);
diff --git a/gremlin-test/features/map/Map.feature 
b/gremlin-test/features/map/Map.feature
index 8d1029f..5f404ea 100644
--- a/gremlin-test/features/map/Map.feature
+++ b/gremlin-test/features/map/Map.feature
@@ -106,3 +106,19 @@ Feature: Step - map()
       | v[josh] |
       | v[ripple] |
       | v[peter]  |
+
+  Scenario: g_V_mapXconstantXnullXX
+    Given the modern graph
+    And the traversal of
+      """
+      g.V().map(__.constant(null))
+      """
+    When iterated to list
+    Then the result should be unordered
+      | result |
+      | null |
+      | null |
+      | null |
+      | null |
+      | null |
+      | null |
\ No newline at end of file
diff --git 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
index 9006fec..35faa03 100644
--- 
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
+++ 
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/map/MapTest.java
@@ -31,9 +31,11 @@ import org.junit.runner.RunWith;
 import java.util.List;
 
 import static org.apache.tinkerpop.gremlin.LoadGraphWith.GraphData.MODERN;
+import static 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.constant;
 import static 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.select;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 /**
@@ -53,6 +55,8 @@ public abstract class MapTest extends 
AbstractGremlinProcessTest {
 
     public abstract Traversal<Vertex, Vertex> get_g_V_mapXselectXaXX();
 
+    public abstract Traversal<Vertex, Vertex> get_g_V_mapXconstantXnullXX();
+
     @Test
     @LoadGraphWith(MODERN)
     public void g_VX1X_mapXnameX() {
@@ -139,6 +143,19 @@ public abstract class MapTest extends 
AbstractGremlinProcessTest {
         assertEquals(6, counter);
     }
 
+    @Test
+    @LoadGraphWith(MODERN)
+    public void g_V_mapXconstantXnullXX() {
+        final Traversal<Vertex, Vertex> traversal = 
get_g_V_mapXconstantXnullXX();
+        printTraversalForm(traversal);
+        int counter = 0;
+        while (traversal.hasNext()) {
+            counter++;
+            assertNull(traversal.next());
+        }
+        assertEquals(6, counter);
+    }
+
     public static class Traversals extends MapTest {
         @Override
         public Traversal<Vertex, String> get_g_VX1X_mapXnameX(final Object 
v1Id) {
@@ -169,5 +186,10 @@ public abstract class MapTest extends 
AbstractGremlinProcessTest {
         public Traversal<Vertex, Vertex> get_g_V_mapXselectXaXX() {
             return g.V().as("a").map(select("a"));
         }
+
+        @Override
+        public Traversal<Vertex, Vertex> get_g_V_mapXconstantXnullXX() {
+            return g.V().map(constant(null));
+        }
     }
 }
diff --git 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
index ce39953..32a77f2 100644
--- 
a/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
+++ 
b/tinkergraph-gremlin/src/test/java/org/apache/tinkerpop/gremlin/tinkergraph/process/traversal/strategy/decoration/OptionsStrategyTest.java
@@ -21,7 +21,7 @@ package 
org.apache.tinkerpop.gremlin.tinkergraph.process.traversal.strategy.deco
 import org.apache.tinkerpop.gremlin.process.traversal.Traverser;
 import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversal;
 import 
org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource;
-import org.apache.tinkerpop.gremlin.process.traversal.step.map.MapStep;
+import org.apache.tinkerpop.gremlin.process.traversal.step.map.ScalarMapStep;
 import 
org.apache.tinkerpop.gremlin.process.traversal.strategy.decoration.OptionsStrategy;
 import org.apache.tinkerpop.gremlin.structure.Graph;
 import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph;
@@ -54,7 +54,7 @@ public class OptionsStrategyTest {
 
     private static void assertOptions(final GraphTraversalSource optionedG) {
         GraphTraversal t = optionedG.inject(1);
-        t = t.asAdmin().addStep(new MapStep<Object, Object>(t.asAdmin()) {
+        t = t.asAdmin().addStep(new ScalarMapStep<Object, Object>(t.asAdmin()) 
{
             @Override
             protected Object map(final Traverser.Admin<Object> traverser) {
                 final OptionsStrategy strategy = 
traversal.asAdmin().getStrategies().getStrategy(OptionsStrategy.class).get();

Reply via email to