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.
>>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>
>>>>>
>>>>
>>
>>