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