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