Hi Dylan,

Your email is excellent. Thank you for breaking things down for me. Here are 
some responses.

> 1. Method overloading :
> 
> abstract class Query {
>    public function has(PropertyKey $key); //1
>    public function has(PropertyKey $key, Object $value); //2
>    public function has(Label $label, String $value); //3
>    public function has(VertexId $id, Long $value); //4
>    public function has(VertexId $id, Int $value); //5
>    public function has(VertexId $id, Predicate $p); //6
> }
> 
> The above is illegal in languages like PHP (or javascript?). Instead we're 
> stuck with :
> 
> abstract class Query {
>    public function has(Array $args);
> }
> 
> We're then left to figure out what is what in the array and sort out how we 
> need to stringify the output. 

I was thinking, why would you need to introspect into the array? Just 
toString() each element in the array with a comma (,) in between. For instance:

* has("age",32) ==> has(["age",32]) ==> has("age",32) // all String array 
element need " " wrappers.
* has("age") ==> has(["age"]) ==> has("age")
* has("person","name","marko") ==> has(["person","name","marko"]) ==> 
has("person","name","marko")

Thus, Gremlin-PHP have one has()-method and that method just iterates the 
arguments and toString()'s thing accordingly with comma deliminators.

> If the user does $g->V()->has("label", "user") do we add quotes to the first 
> argument or is it a label/id? What about the second argument, is it a 
> predicate? etc.  This gets complexe very quickly.

The universal rule --- if its a String add quotes. If its not, don't. 

$id -> "~id"
$label -> "~label"

$g->V()->has($label,"user")

> And what if I had $g->V()->has("id", 36) . PHP only supports Int so one of 
> the two signatures (4 or 5) needs to give as we have a major conflict. This 
> example is fictional for has() but I've run into this on a couple of other 
> methods, just can't remember which. 

Yea, that sucks. Well, you could do this:

$g->V()->has($id,Number::long(36))  ==> g.V().has("id",36l)

This would, of course, bind you to Gremlin-Groovy as the ultimate ScriptEngine.

> Another example would be  g.V().has(id, neq(m)) . We could imagine the 
> following PHP equivalent $g->V()->has(new Id(), Predicate::neq("m")) where 
> Id() is a class that helps us recognize this type, and neq() a static method 
> of Predicate. However "m" has to be passed as string and we have no clue what 
> m is... is this a string or a binding or a server side variable? More on this 
> in point 2.

Well, this is the same problem in Gremlin-Java. where() is ALWAYS bindings and 
has() is ALWAYS objects. Thus:

$g->V()->where("a",Predicate::neq("m")) ==> g.V().where("a",neq("m")) // again 
strings always get " "-wrappers.

> To close things off here there's also the case of signatures like 
> out(String... edgeLabels) that need their own logic.

Again, just toString() each object in the array and insert commas between.

$g->V()->out(["created","knows"]) ==> g.V().out("created","knows")


> Conclusion: There's a lot of manual work that needs to go into separating the 
> logic between signatures and handling special cases. Part of this can be 
> automated if your language supports magic getters and setters by parsing the 
> javadocs for example. But not only is that an if, the rest will still be 
> manual. This step is maintenance heavy.

I see the biggest pains being:

        1. Having to implement each method.
        2. Having to have helper classes for P, T, Order, Column, etc.

This is simply a matter of fat fingering stuff in and not anything 
implementation-wise that is problematic -- ????….

> 2. Conflicts
> 
> Because we're manipulating strings it's really hard to tell a few items 
> appart (binding vs server variable vs string; Theres a reason why I separate 
> binding and variable). 
> 
> For instance in the example above of gremlin : g.V().has(id, neq(m)) vs PHP: 
> $g->V()->has(new Id(), Predicate::neq("m")) we don't know what to make of m. 
> Is this a binding or a string or even a variable that was previously set in 
> the session? There is no clean way of working around this.
> 
> Firstly because bindings tend to be handled on a different layer than the 
> query builder.
> Secondly because methods that will help in avoiding the conflicts will also 
> lose typing data.
> For example : $g->V()->has(new Id(), Predicate::neq(Query::variable("m"))) 
> could generate the proper query by outputting m without quotes but we don't 
> know what type m is so in some cases it might be tricky to select the proper 
> signature.
> 
> Conclusion: there are a number of ways around this point. We use prefixes B_m 
> or V_m and a hack to ignore signatures altogether when in this scenario. It's 
> not that these aren't solve-able they just aren't trivial.

Hm. Yea, I'm not to smart about sever variables. Out of my butt you could 
create a "crazy String" for those an then do replaceAll-style updates.

g.V().out("%%x")

replaceAll("%%x",x)

?


> 3. API
> 
> Why we would need traversal, graph, vertex and edge APIs are quite self 
> explanatory for everyday work with Gremlin. I'm just going to expose why we 
> would also require some Java classes as well. 
> 
> Because JSON is lossy by nature we often have to cast variables to certain 
> types. For example by submitting these kind of scripts : 
> g.V(1).property("date", new Date(B_m)); with B_m = timestamp. This is just 
> another case that is difficult to cover. 
> 
> This adds onto the other points in making a gremlin language variant 
> non-trivial.
> 
> All of the above can be worked around by using an injection method that just 
> appends a string to the query : $g->customStep("V().has(id, neq(m))") but 
> that's besides the point.


Ah. Classy. Note that in ?3.2.1? we might support script()-step.

g.V().script("out().map{ it.name }")

…to enable lambdas in remote'd traversals (Server or OLAP).

For your Date example, you would have to have a special "toString()" for PHP 
dates to Java dates (or whichever backend ScriptEngine is being used).

$g->V()->property("data", phpDate)

Your Array-string-ifier would not just call toString() blindly on the objects 
of the array arguments, but would do stuff like:

if(object instanceof String)
  return \" + object.toString() + "\;
else if(object instanceof Date)
  return "new Date(…)";
else
  return object.toString()


> Final Conclusion: It's not a trivial task. Of course the examples above are 
> very verbose and achieving something closer to gremlin in style is possible 
> but there are always going to be "gotchas" users will need to keep in mind.  
> A while back in TP2 I released a php library for this (the one we currently 
> use in our projects). I decided to remove it as it was too much maintenance 
> to get it to work across user causes so I decided to concentrate on our own 
> one (some choices made in 2. wouldn't have worked for other cases)
> I'm convinced there's got to be a way of reconciling everything and getting 
> this to work flawlessly but it's going to require a lot of thought/work
> 
> 
> PS: I mentioned some other points like managing multiple versions of gremlin 
> (for two lines of releases) which is a real headache. 
> For performance it may be good to allow the builder to handle multiple lines, 
> which comes with it's load of complications as well. 
> And then there's the ability to "block" queries and either inject them into 
> each other or merge them together which simplifies unit testing and extends 
> functionality :
> 
> $query = $g->V()->out("likes")->flag("flagname")->has("age", 20);
> // Some logic here accesses new information and realizes the query needs 
> altering
> $query->getFlag("flagname")->out("hates", true) // true for merge
> $query->toString(); // g.V().out('likes', hates').has('age', 20)
> 
> But this point alone could warrant it's own email as it is relatively 
> complex. Though TP3 has simplified some cases thanks to union() and some 
> other steps.
> 
> Our builder supports all of the above so if you have any questions feel free 
> to ask me.
> 
> Phew that was long. I'll add this to the ticket in a bit.


Yes, maintenance seems the biggest pain. Every new method to Gremlin-Java 
requires updates to Gremlin-PHP ---- perhaps there is a programmatic way to 
introspect the Java source file (or JavaDoc) and generate the code 
automagically?

public GraphTraversal out(final String… edgeLabels) 
        ==auto-write==>
out(Array… edgeLabels) {
  $string -> $string + ".out(" + StringHelper::toString(edgeLabels) + ")";
}


If you could do that, then the only code you actually have to write/maintain 
(besides the introspector above) is StringHelper which does all the fancy 
String conversion of arguments. 

??.

Thanks Dylan for your time,
Marko.

http://markorodriguez.com

> 
> On Tue, Apr 12, 2016 at 4:37 PM, Marko Rodriguez <okramma...@gmail.com> wrote:
> Hello everyone,
> 
> Please see the section entitled "Host Language Embedding" here:
>       http://www.planettinkerpop.org/#gremlin (3 sections down)
> 
> When I was writing up this section, I noticed that most of the language 
> drivers that are advertised on our homepage 
> (http://tinkerpop.incubator.apache.org/#graph-libraries) know how to talk to 
> Gremlin Server via web sockets, REST, etc., but rely on the user to create a 
> String of their graph traversal and submit it. For instance, here is a 
> snippet from the Gremlin-PHP documentation:
> 
> $db = new Connection([
>     'host' => 'localhost',
>     'graph' => 'graph',
>     'username' => 'pomme',
>     'password' => 'hardToCrack'
> ]);
> //you can set $db->timeout = 0.5; if you wish
> $db->open();
> $db->send('g.V(2)');
> //do something with result
> $db->close();
> 
> $db->send(String) is great, but it would be better if the user didn't have to 
> leave PHP.
> 
> Please see this ticket:
>       https://issues.apache.org/jira/browse/TINKERPOP-1232
> 
> I think for non-JVM languages, it would be nice if these drivers (PHP, 
> JavaScript, Python, etc.) didn't require the user to explicitly create 
> Gremlin-XXX Strings, but instead either used JINI or model-3 in the ticket 
> above. Lets look at model-3 as I think its the easiest and more general.
> 
> For instance, they would have a class in their native language that would 
> mirror the GraphTraversal API. *** I don't know any other languages well 
> enough, so I'm just going to do this in Groovy :), hopefully you get the 
> generalized point. ***
> 
> public class Test {
> 
>   String s;
> 
>   public Test(final String source) {
>     s = source;
>   }
> 
>   public Test() {
>     s = "";
>   }
> 
>   public Test V() {
>     s = s + ".V()";
>     return this;
>   }
> 
>   public Test outE(final String label) {
>     s = s + ".outE(\"${label}\")";
>     return this;
>   }
> 
>   public Test repeat(final Test test) {
>     s = s + ".repeat(${test.toString()})";
>     return this;
>   }
> 
>   public String toString() {
>     return s;
>   }
> }
> 
> Then, via fluency (function composition) and nesting, you could generate a 
> Gremlin-Groovy (or which ever ScriptEngine language) traversal String in the 
> backend.
> 
> gremlin> g = new Test("g");
> ==>g
> gremlin> g.V().outE("knows")
> ==>g.V().outE("knows")
> gremlin>
> gremlin> g = new Test("g");
> ==>g
> gremlin> g.V().repeat(new Test().outE("knows"))
> ==>g.V().repeat(.outE("knows"))
> gremlin>
> 
> From there, that String is then submitted as you normally do with your 
> driver. For instance, with Gremlin-PHP, via $db->send(String). 
> 
> Of course, if your driver is already on a JVM language, there is no reason to 
> do this (e.g. Gremlin-Scala), but if you are not on the JVM, this gives the 
> user host language embedding and a more natural "look and feel." Moreover, if 
> your language doesn't use "dot notation," you would use the natural idioms of 
> your language. 
> 
> $g->V->outE("knows")
> 
> If anyone is interested in updating their non-JVM language driver to use this 
> model, I would like to write a blog post about it. Or perhaps, a tutorial for 
> for language designers.
> 
> Thoughts?,
> Marko.
> 
> http://markorodriguez.com
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Gremlin-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to gremlin-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/gremlin-users/47A92EFF-CB36-41EA-B252-6823A42F4D7B%40gmail.com.
> For more options, visit https://groups.google.com/d/optout.
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "Gremlin-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to gremlin-users+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/gremlin-users/CAE0QJeqntbEk70yg_d2SACxaKxA995Z8SL5_3JRaxzsQCCOMbw%40mail.gmail.com.
> For more options, visit https://groups.google.com/d/optout.

Reply via email to