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

Reply via email to