Hello Matt,
I merged your pull request. First, great PR -- thank you for the test cases.
Next, the failures your tests identified are a function of the non-existent
labels in Scope.local situations. What happens is that the ScopingStrategy says
"well, judging from the an analysis of the as() labels, it looks like this
Scoping step doesn't access path information, but instead, map information."
https://github.com/apache/incubator-tinkerpop/blob/master/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/strategy/finalization/ScopingStrategy.java#L51-L54
However, if there are no map objects flowing into the Scope step, then a
ClassCastException occurs. The remedy to this is simple. ScopingStrategy stays
the same --- if there aren't path labels, then its okay to think you are in
Scope.local (mainly because its the most efficient state to be in as path
calculations are turned off). However, if the object that the Scoping step
pulls in is NOT a Map, it shouldn't get upset and throw a ClassCastException.
Instead, it should simply assume Collections.emptyMap().
https://github.com/apache/incubator-tinkerpop/blob/master/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/Scoping.java#L70-L74
Collections.emptyMap() is the analogous structure to EmptyPath.
https://github.com/apache/incubator-tinkerpop/blob/master/gremlin-core/src/main/java/org/apache/tinkerpop/gremlin/process/traversal/step/util/EmptyPath.java
Now missing labels in a Scoping step behave the same in both Scope.local and
Scope.global.
Thanks again for your help,
Marko.
http://markorodriguez.com
P.S. I notice a lot that your GroovyXXXTest need "fixing up" before merging to
master/. Do you build the code on your local machine? Note the diff with
GroovySelectTest.
https://github.com/apache/incubator-tinkerpop/commit/161250061a1230ad293915b1d5d19a647d202aae
On Jun 22, 2015, at 8:58 PM, Marko Rodriguez <[email protected]> wrote:
> Hello,
>
> This is what I'm doing first thing tomorrow morning.
>
> Marko.
>
> http://markorodriguez.com
>
> On Jun 22, 2015, at 7:53 PM, Matt Frantz <[email protected]> wrote:
>
>> Marko, have you had a chance to look at this PR? Do these use cases make
>> sense? Any idea why they are failing? Should we reopen #619 as a reminder
>> to keep looking at this PR? It would be nice to settle this for GA.
>>
>> On Sat, Jun 20, 2015 at 9:27 AM, Matt Frantz <[email protected]>
>> wrote:
>>
>>> Since this was really about creating regressions for TINKERPOP3-619, I
>>> created a PR with those regressions.
>>>
>>> https://github.com/apache/incubator-tinkerpop/pull/86
>>>
>>> As stated in the PR, a few of these cases now fail, so take a look and let
>>> me know if I can help.
>>>
>>> On Fri, Jun 19, 2015 at 7:34 PM, Marko Rodriguez <[email protected]>
>>> wrote:
>>>
>>>> Hey Matt,
>>>>
>>>> Can you make a "formal" ticket about the problem you are seeing, please?
>>>>
>>>> Thanks,
>>>> Marko.
>>>>
>>>> http://markorodriguez.com
>>>>
>>>> On Jun 19, 2015, at 7:09 PM, Matt Frantz <[email protected]>
>>>> wrote:
>>>>
>>>>> Cool. Can't wait to get my hands on GA!
>>>>>
>>>>> I just read through SelectStep/SelectOneStep (again), and I'm pretty
>>>> sure
>>>>> that if you do a select of a nonexistent label, it will stop the
>>>> traversal
>>>>> rather than raise "step with provided label does not exist" exception,
>>>> like
>>>>> in olden times. That is because Scoping.getOptionalScopeValueByKey
>>>> checks
>>>>> Path.hasLabel. That makes the Path.get exception case unreachable from
>>>>> select, which is what we want. Not sure what to do about that, if
>>>>> anything, but I am unsure about regression test coverage. This
>>>> requirement
>>>>> came from TINKERPOP3-619 (select should not throw).
>>>>>
>>>>> g.V().select('a') [should produce nothing]
>>>>> g.V().valueMap().select('a') [should produce nothing]
>>>>>
>>>>>
>>>>> On Fri, Jun 19, 2015 at 12:24 PM, Marko Rodriguez <[email protected]
>>>>>
>>>>> wrote:
>>>>>
>>>>>> Hi Matt,
>>>>>>
>>>>>> Okay, we now have:
>>>>>>
>>>>>> Pop.first
>>>>>> Pop.last
>>>>>> Pop.all
>>>>>>
>>>>>> And there are two "get" methods:
>>>>>>
>>>>>> A get(label) // could be a singleton, list, or exception
>>>>>> A get(pop,label) // single (or exception if doesn't exist) or
>>>> list
>>>>>> (empty list if does not exist)
>>>>>>
>>>>>> Everything looks the same except:
>>>>>>
>>>>>> path.<List>get(Pop.all, "a").size()
>>>>>>
>>>>>> Good stuff man. Appreciate your patience on the matter --- that was
>>>> like a
>>>>>> 2 month ticket.
>>>>>>
>>>>>> Marko.
>>>>>>
>>>>>> http://markorodriguez.com
>>>>>>
>>>>>> On Jun 16, 2015, at 1:53 PM, Matt Frantz <[email protected]>
>>>>>> wrote:
>>>>>>
>>>>>>> In contrast to the current "Path.get" (which aligns with the current
>>>>>>> "select"), specifying Pop.all would ensure that you get a List even if
>>>>>>> there is only one element. Thus, one could choose between the
>>>>>> "containers
>>>>>>> only when necessary" API and the "predictable type" API.
>>>>>>>
>>>>>>> For context, my application contains loops (repeat-until) that contain
>>>>>>> labeled steps. Ahead of time, you don't know how many iterations you
>>>>>> will
>>>>>>> get. Thus, with the current "select" behavior, you don't know whether
>>>> you
>>>>>>> will get a single element (one iteration) or a List (more than one
>>>>>>> iteration), so there has to be a check and a conversion into List. I
>>>>>> would
>>>>>>> almost always prefer a predictable type, so I would use Pop.all when I
>>>>>> want
>>>>>>> a List. (Of course, I sometimes want Pop.last, but that problem is
>>>> now
>>>>>>> solved.)
>>>>>>>
>>>>>>> If you change Path.get(label) to call Path.get(Pop.all, label), then
>>>>>> select
>>>>>>> would have to be modified, provided you want to preserve the
>>>> "containers
>>>>>>> only when necessary" API.
>>>>>>>
>>>>>>> On Tue, Jun 16, 2015 at 5:13 AM, Marko Rodriguez <
>>>> [email protected]>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Hi Matt,
>>>>>>>>
>>>>>>>> So I did Pop.first ("return collection[0]") and Pop.last (i.e.
>>>> "return
>>>>>>>> collection[collection.size() - 1]"). Pushed.
>>>>>>>>
>>>>>>>> Next, so by Pop.all you mean "return collection" ? Can you explain
>>>> the
>>>>>>>> context in which this enum would be used? Are you assuming that
>>>>>>>> Path.getSingle() goes away and we have Path.get(Pop, label) with
>>>>>>>> Path.get(label) defaulting to Pop.all?
>>>>>>>>
>>>>>>>> Thanks for your help with this,
>>>>>>>> Marko.
>>>>>>>>
>>>>>>>> http://markorodriguez.com
>>>>>>>>
>>>>>>>> On Jun 15, 2015, at 10:56 AM, Matt Frantz <
>>>> [email protected]>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> How about a third choice that always returns a List? Pop.all? This
>>>>>>>> would
>>>>>>>>> provide the Java Generic type safety that fills our hearts with
>>>> light.
>>>>>>>>>
>>>>>>>>> On Mon, Jun 15, 2015 at 9:49 AM, Matt Frantz <
>>>>>> [email protected]
>>>>>>>>>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>> That works for me.
>>>>>>>>>>
>>>>>>>>>> On Mon, Jun 15, 2015 at 8:55 AM, Marko Rodriguez <
>>>>>> [email protected]>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>> Ah. The plot thickens.
>>>>>>>>>>>
>>>>>>>>>>> I prefer to keep limit() and tail().
>>>>>>>>>>>
>>>>>>>>>>> What if we do:
>>>>>>>>>>>
>>>>>>>>>>> Pop.first (was Pop.tail)
>>>>>>>>>>> Pop.last (was Pop.head)
>>>>>>>>>>>
>>>>>>>>>>> Is then everything else consistent?
>>>>>>>>>>>
>>>>>>>>>>> Marko.
>>>>>>>>>>>
>>>>>>>>>>> http://markorodriguez.com
>>>>>>>>>>>
>>>>>>>>>>> On Jun 15, 2015, at 9:15 AM, Matt Frantz <
>>>> [email protected]
>>>>>>>
>>>>>>>>>>> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> In addition to unfold().tail(), there is tail(local), which is
>>>>>>>>>>> consistent
>>>>>>>>>>>> with unfold().tail() in that it grabs the "end" of the List (or
>>>>>> Map).
>>>>>>>>>>>>
>>>>>>>>>>>> By "consistent throughout", I guess you mean "select's use of
>>>>>>>> head/tail
>>>>>>>>>>>> terminology should be consistent with established terminology in
>>>>>> graph
>>>>>>>>>>>> theory." You also say that List.iterator() emits values
>>>>>> left-to-right
>>>>>>>>>>>> (tail to head). However, the terminology that I am accustomed
>>>> to is
>>>>>>>>>>>> described on the wiki for a Linked list: "The 'head' of a list is
>>>>>> its
>>>>>>>>>>> first
>>>>>>>>>>>> node. The 'tail' of a list may refer either to the rest of the
>>>> list
>>>>>>>>>>> after
>>>>>>>>>>>> the head, or to the last node in the list."
>>>>>>>>>>>>
>>>>>>>>>>>> This terminology resonates in a cursory search ("stream head
>>>> tail")
>>>>>> to
>>>>>>>>>>>> describe streams, i.e. "head" means the first thing that comes
>>>> out
>>>>>> of
>>>>>>>> a
>>>>>>>>>>>> stream, while "tail" means "everything except the head." With an
>>>>>>>>>>> integer
>>>>>>>>>>>> argument, "head(n)" resembles Gremlin's "limit(n)", if you think
>>>> of
>>>>>> a
>>>>>>>>>>>> Gremlin traversal as a stream that produces traversers.
>>>>>>>>>>>>
>>>>>>>>>>>> The use of "head" and "tail" as Unix utilities is currently
>>>>>> consistent
>>>>>>>>>>> with
>>>>>>>>>>>> the tail step's usage, in that they refer, respectively, to the
>>>>>> first
>>>>>>>>>>> and
>>>>>>>>>>>> last objects in the stream.
>>>>>>>>>>>>
>>>>>>>>>>>> I feel that the two uses of "tail" should be consistent with each
>>>>>>>> other
>>>>>>>>>>>> within Gremlin, but I can see that they are currently drawn from
>>>>>>>>>>> different
>>>>>>>>>>>> disciplines of computer science. My preference would be to
>>>> replace
>>>>>>>>>>>> "limit/tail" with "first/last" to avoid such ambiguity. Then, we
>>>>>> can
>>>>>>>>>>> swap
>>>>>>>>>>>> Pop head/tail as it was in the beginning.
>>>>>>>>>>>>
>>>>>>>>>>>> The idea of making "limit" and "tail" more obviously symmetric
>>>>>> belies
>>>>>>>>>>> the
>>>>>>>>>>>> origin of "limit" as a terminology ported from RDBMS (I
>>>> presume). I
>>>>>>>> am
>>>>>>>>>>> not
>>>>>>>>>>>> opposed to synonyms/aliases, although the Gremlin language may be
>>>>>> rich
>>>>>>>>>>>> enough without them.
>>>>>>>>>>>>
>>>>>>>>>>>> I'd be happy to help with whatever solution is agreeable to the
>>>>>>>>>>> community.
>>>>>>>>>>>> I'll have some TP3 budget in a couple of days.
>>>>>>>>>>>>
>>>>>>>>>>>> My two cents.
>>>>>>>>>>>>
>>>>>>>>>>>> On Mon, Jun 15, 2015 at 6:55 AM, Marko Rodriguez <
>>>>>>>> [email protected]>
>>>>>>>>>>>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> So the way the select() puts things into a List (i.e.
>>>> Path.get()),
>>>>>>>>>>>>> currently, is good:
>>>>>>>>>>>>>
>>>>>>>>>>>>> gremlin> g.V().as('a').out('created').as('a').select('a')
>>>>>>>>>>>>> ==>[v[1], v[3]]
>>>>>>>>>>>>> ==>[v[4], v[5]]
>>>>>>>>>>>>> ==>[v[4], v[3]]
>>>>>>>>>>>>> ==>[v[6], v[3]]
>>>>>>>>>>>>>
>>>>>>>>>>>>> In the first result, the "tail/start/initial" is v[1] and the
>>>>>>>>>>>>> "head/end/terminal" is v[3]. That lines up with the tail/head
>>>>>>>>>>> terminology
>>>>>>>>>>>>> in graph theory. However, what is off is that Pop.head/tail is
>>>>>> wrong:
>>>>>>>>>>>>>
>>>>>>>>>>>>> gremlin> g.V().as('a').out('created').as('a').select(head,'a')
>>>>>>>>>>>>> ==>v[1]
>>>>>>>>>>>>> ==>v[4]
>>>>>>>>>>>>> ==>v[4]
>>>>>>>>>>>>> ==>v[6]
>>>>>>>>>>>>>
>>>>>>>>>>>>> Pop.head should return v[3] (for the first result). This is a
>>>>>> simple
>>>>>>>>>>> fix
>>>>>>>>>>>>> of just reversing the meaning of Pop.head/tail (2 line fix).
>>>>>>>>>>>>>
>>>>>>>>>>>>> However, the reason you flipped Pop.head/tail to begin with is
>>>>>>>> because
>>>>>>>>>>> you
>>>>>>>>>>>>> wanted it to align with unfold().tail(). So lets look at
>>>> unfold().
>>>>>>>>>>>>>
>>>>>>>>>>>>> gremlin>
>>>>>>>>>>> g.V().as('a').out('created').as('a').select('a').limit(1).unfold()
>>>>>>>>>>>>> ==>v[1]
>>>>>>>>>>>>> ==>v[3]
>>>>>>>>>>>>> gremlin>
>>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>> g.V().as('a').out('created').as('a').select('a').limit(1).unfold().tail(1)
>>>>>>>>>>>>> ==>v[3]
>>>>>>>>>>>>>
>>>>>>>>>>>>> This should emit v[1]. Bumskies! However, this is about how the
>>>>>>>>>>> "unfolded"
>>>>>>>>>>>>> Iterable is iterated.
>>>>>>>>>>>>>
>>>>>>>>>>>>> gremlin> [1,2,3,4].iterator()
>>>>>>>>>>>>> ==>1
>>>>>>>>>>>>> ==>2
>>>>>>>>>>>>> ==>3
>>>>>>>>>>>>> ==>4
>>>>>>>>>>>>>
>>>>>>>>>>>>> Unfortunately, when you do List.iterator(), it emits values
>>>>>>>>>>> left-to-right
>>>>>>>>>>>>> (tail to head). Not right-to-left (head to tail). So, we can
>>>> make
>>>>>>>>>>> unfold()
>>>>>>>>>>>>> behave differently by:
>>>>>>>>>>>>>
>>>>>>>>>>>>> gremlin> [1,2,3,4].reverse().iterator()
>>>>>>>>>>>>> ==>4
>>>>>>>>>>>>> ==>3
>>>>>>>>>>>>> ==>2
>>>>>>>>>>>>> ==>1
>>>>>>>>>>>>>
>>>>>>>>>>>>> …but that is no bueno from a memory conservation standpoint. I
>>>>>> would
>>>>>>>>>>> argue
>>>>>>>>>>>>> that unfold() has nothing to do with path-semantics, but
>>>> instead,
>>>>>>>> list
>>>>>>>>>>>>> semantics. Therefore, we can argue (in debate) that
>>>>>> "unfold().tail()"
>>>>>>>>>>> is
>>>>>>>>>>>>> not an anomaly of tail(), but one of unfold().
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thus, to be consistent throughout, all we need to do is flip
>>>>>> Pop.head
>>>>>>>>>>> to
>>>>>>>>>>>>> Pop.tail and vice versa (i.e. as it was originally).
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thoughts?,
>>>>>>>>>>>>> Marko.
>>>>>>>>>>>>>
>>>>>>>>>>>>> http://markorodriguez.com
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Jun 12, 2015, at 12:56 PM, Matt Frantz <
>>>>>>>> [email protected]>
>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> We could do any of the following:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> - Rename the "tail" step (e.g. "last") so that we can flip Pop
>>>>>> back
>>>>>>>>>>> to
>>>>>>>>>>>>>> the way graph theorists presumably expect it to work.
>>>>>>>>>>>>>> - Reverse the way "select" puts things in a List, and flip Pop
>>>>>> back.
>>>>>>>>>>>>>> - Rename Pop head/tail to oldest/newest (or first/last)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Fri, Jun 12, 2015 at 5:14 AM, Marko Rodriguez <
>>>>>>>>>>> [email protected]>
>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hm… I see what you are saying. The problem is that in graph
>>>>>> theory,
>>>>>>>>>>>>>>> head/tail terms are reversed in Path.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Marko.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> http://markorodriguez.com
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Jun 11, 2015, at 3:39 PM, Matt Frantz <
>>>>>>>> [email protected]
>>>>>>>>>>>>
>>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Another symmetry I was aiming for:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> ...select(tail, 'a')
>>>>>>>>>>>>>>>> ...select('a').by(unfold.tail(1))
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Thu, Jun 11, 2015 at 2:16 PM, Matt Frantz <
>>>>>>>>>>>>> [email protected]
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I was trying to reconcile the way that the range/limit/tail
>>>>>> steps
>>>>>>>>>>>>>>> operate
>>>>>>>>>>>>>>>>> with how Pop is interpreted. For local scope, the range
>>>>>> ordinals
>>>>>>>>>>> are
>>>>>>>>>>>>>>>>> congruent with the list index ordinals. Thus, "limit(1)"
>>>> means
>>>>>>>>>>>>>>>>> "range(0,1)" which means List.get(0). Since "tail(1)" is
>>>> the
>>>>>>>>>>>>>>> complement of
>>>>>>>>>>>>>>>>> "limit(1)", it means "the highest numbered element" or
>>>>>>>>>>>>>>>>> List.get(List.size()-1).
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I understand your description of a stream, but I was trying
>>>> to
>>>>>>>>>>>>> reconcile
>>>>>>>>>>>>>>>>> the terms with Gremlin and not with streams.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> If you compare a stream with a Unix command line, and how
>>>> the
>>>>>>>>>>> "head"
>>>>>>>>>>>>> and
>>>>>>>>>>>>>>>>> "tail" utilities act, then "head" means "the first lines you
>>>>>> see"
>>>>>>>>>>> and
>>>>>>>>>>>>>>>>> "tail" means "the last lines you see".
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> For global scope, it seems that "limit(1)" means "the first
>>>>>>>>>>> traverser"
>>>>>>>>>>>>>>> and
>>>>>>>>>>>>>>>>> "tail(1)" means "the last traverser". For any Traversal, t,
>>>>>>>>>>>>> t.limit(1)
>>>>>>>>>>>>>>>>> produces the same thing as t.toList().get(0).
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Good news on select(pop)!
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On Thu, Jun 11, 2015 at 11:43 AM, Marko Rodriguez <
>>>>>>>>>>>>> [email protected]
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Hey,
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Yes -- "first = tail" and "last = head".
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> A path grows with its "head growing" .. its tail is static.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> a-->b-->c-->d-->e
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> the tail is always "a"…the head is "a", then "b", then "c",
>>>>>> then
>>>>>>>>>>>>> "d"….
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> In a list or stream, the tail is the first element.
>>>>>>>>>>>>>>>>>> - get(0) for list
>>>>>>>>>>>>>>>>>> - stream().toList().get(0)
>>>>>>>>>>>>>>>>>> In a list or stream, the head is always the most current
>>>>>>>> element.
>>>>>>>>>>>>>>>>>> - get(list.size() - 1) for list
>>>>>>>>>>>>>>>>>> - stream().next()
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> …..?
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> I will hide your interface inside ImmutablePath just for my
>>>>>>>> sanity
>>>>>>>>>>>>> :).
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> BTW: select(pop) is on its way.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Marko.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> http://markorodriguez.com
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> On Jun 11, 2015, at 12:30 PM, Matt Frantz <
>>>>>>>>>>>>> [email protected]>
>>>>>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> limit(1) means "first" and tail(1) means "last" (in both
>>>>>> global
>>>>>>>>>>> and
>>>>>>>>>>>>>>>>>> local
>>>>>>>>>>>>>>>>>>> manifestations).
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> In the Path.get results, you get a list whose first
>>>> element
>>>>>> is
>>>>>>>>>>> the
>>>>>>>>>>>>>>>>>>> first/oldest object matching the step label, so that felt
>>>>>> like
>>>>>>>>>>>>> "head"
>>>>>>>>>>>>>>> to
>>>>>>>>>>>>>>>>>>> me, while the last element is the most recent and thus
>>>>>> "tail".
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> get => [a,b,c,d]
>>>>>>>>>>>>>>>>>>> getSingle(head) => a
>>>>>>>>>>>>>>>>>>> getSingle(tail) => d
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> In other words the following should be equal:
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> ...map{it->it.path().get('foo')}.tail(local, 1)
>>>>>>>>>>>>>>>>>>> ...map{it->it.path().getSingle(tail, 'foo')}
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> I used ImmutablePathImpl because I needed HeadPath to have
>>>>>> the
>>>>>>>>>>>>>>>>>>> getSingleTail/getSingleHead methods, too. Thus, a common
>>>>>>>>>>> interface
>>>>>>>>>>>>>>>>>> between
>>>>>>>>>>>>>>>>>>> ImmutablePath and HeadPath was required. The interface
>>>> has
>>>>>>>>>>> package
>>>>>>>>>>>>>>>>>> scope,
>>>>>>>>>>>>>>>>>>> so it is not part of the public API.
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> On Thu, Jun 11, 2015 at 11:12 AM, Marko Rodriguez <
>>>>>>>>>>>>>>> [email protected]
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> Hi Matt,
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> limit(1) means the most recent value.
>>>>>>>>>>>>>>>>>>>> tail(1) means the oldest value. ?
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> path: [a,b,c,d]
>>>>>>>>>>>>>>>>>>>> a = tail
>>>>>>>>>>>>>>>>>>>> d = head
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> No?
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> Also, why did you do ImmutablePathImpl? Seems that can
>>>> just
>>>>>> be
>>>>>>>>>>>>>>> private
>>>>>>>>>>>>>>>>>>>> methods inside of ImmutablePath?
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>>>>>> Marko.
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> http://markorodriguez.com
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>> On Jun 11, 2015, at 11:56 AM, mhfrantz <
>>>> [email protected]>
>>>>>>>>>>> wrote:
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> GitHub user mhfrantz opened a pull request:
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> https://github.com/apache/incubator-tinkerpop/pull/76
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> TINKERPOP3-700 Path getSingle/getList improvements
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> As requested in the comments of TINKERPOP3-700. I also
>>>>>>>>>>> reversed
>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>>>>>> sense of `Pop` to align with `tail(local)`. Thus
>>>> `Pop.tail`
>>>>>>>> now
>>>>>>>>>>>>>>> means
>>>>>>>>>>>>>>>>>> the
>>>>>>>>>>>>>>>>>>>> most recent value.
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> You can merge this pull request into a Git repository by
>>>>>>>>>>> running:
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> $ git pull
>>>>>> https://github.com/RedSeal-co/incubator-tinkerpop
>>>>>>>>>>>>>>>>>>>> TINKERPOP3-700-Path-getSingle
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Alternatively you can review and apply these changes as
>>>> the
>>>>>>>>>>> patch
>>>>>>>>>>>>>>> at:
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>
>>>>>> https://github.com/apache/incubator-tinkerpop/pull/76.patch
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> To close this pull request, make a commit to your
>>>>>>>> master/trunk
>>>>>>>>>>>>>>> branch
>>>>>>>>>>>>>>>>>>>>> with (at least) the following in the commit message:
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> This closes #76
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> ----
>>>>>>>>>>>>>>>>>>>>> commit e1e1a40b068ffe6da3d321256d6200dee0504074
>>>>>>>>>>>>>>>>>>>>> Author: mhfrantz <[email protected]>
>>>>>>>>>>>>>>>>>>>>> Date: 2015-06-11T16:47:41Z
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Add javadoc for Path getList/getSingle
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> commit 4939cf0a22c4fc44a4f86ed3e023fa30e4e872cc
>>>>>>>>>>>>>>>>>>>>> Author: mhfrantz <[email protected]>
>>>>>>>>>>>>>>>>>>>>> Date: 2015-06-11T17:10:27Z
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Reverse sense of Path.getSingle Pop to align with
>>>>>> tail(local)
>>>>>>>>>>> step
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> commit 027d6319f9ff06ca26d785e83bf17b21364c3dca
>>>>>>>>>>>>>>>>>>>>> Author: mhfrantz <[email protected]>
>>>>>>>>>>>>>>>>>>>>> Date: 2015-06-11T17:51:23Z
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Optimize MutablePath.getSingle
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> commit 5e9ad8d7dff6c63b9746147a1d255cbf7258cea3
>>>>>>>>>>>>>>>>>>>>> Author: mhfrantz <[email protected]>
>>>>>>>>>>>>>>>>>>>>> Date: 2015-06-11T17:52:43Z
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> Optimize ImmutablePath getSingle and getList
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> ----
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>> If your project is set up for it, you can reply to this
>>>>>> email
>>>>>>>>>>> and
>>>>>>>>>>>>>>> have
>>>>>>>>>>>>>>>>>>>> your
>>>>>>>>>>>>>>>>>>>>> reply appear on GitHub as well. If your project does not
>>>>>> have
>>>>>>>>>>> this
>>>>>>>>>>>>>>>>>>>> feature
>>>>>>>>>>>>>>>>>>>>> enabled and wishes so, or if the feature is enabled but
>>>> not
>>>>>>>>>>>>> working,
>>>>>>>>>>>>>>>>>>>> please
>>>>>>>>>>>>>>>>>>>>> contact infrastructure at [email protected] or
>>>>>> file
>>>>>>>> a
>>>>>>>>>>>>> JIRA
>>>>>>>>>>>>>>>>>>>> ticket
>>>>>>>>>>>>>>>>>>>>> with INFRA.
>>>>>>>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>>
>>>>
>>>>
>>>
>