myPatterns & LINQ

This page discusses the relationship between custom notations, as implemented by myPatterns, and LINQ technologies (Language INtegrated Queries). To make the discussion concrete, let us consider the following table of persons:
var persons =
[{name: {firstname: "John", lastname: "Smith"}, 
  children:[{firstname: "Eric", gender: "male", born: 1991}, 
            {firstname: "Deborah", gender: "female", born: 1996}]},
 {name: {firstname: "Kevin", lastname: "Carrera"}, 
  children:[]},
 {name: {firstname: "Matt", lastname: "Johnson"}, 
  children:[{firstname: "Sarah", gender: "female", born: 1978},
            {firstname: "Suzy", gender: "female", born: 1979}]},
 {name: {firstname: "Phil", lastname: "Baker"}, 
  children:[{firstname: "Ryan", gender: "male", born: 1990},
            {firstname: "Helen", gender: "female", born: 1975}]}];
The following myPatterns/JS query selects the list of persons having at least one child, the elder child being a boy, and extracts their first name, last name, and year of birth of their elder son:
selectMatching(persons, "{name:{firstname:%f,lastname:%l},children:[{gender:'male',born:%b}|%_]}")
Result:

An equivalent query can be written using a LINQ library for JavaScript, such as JSLINQ:

new JSLINQ(persons)
    .Where(function(x) { return x.children.length > 0 && x.children[0].gender == 'male'; })
    .Select(function(x) { return {f: x.name.firstname, l: x.name.lastname, b: x.children[0].born};})
Result:

As can be seen, the LINQ query is less concise, and lower level, in that it must explicit some tests involving sub-data that are implicit (declaratively defined) in the pattern matching form: that the list of children is non-empty and that the first child is a boy. Furthermore, the LINQ form involves an explicit Select clause that is also implicit in myPatterns/JS. Thus, a pattern matching query is equivalent to a Where clause (filtering data according to its form) plus a Select clause (extracting some sub-data thereof).

However, the LINQ queries are more powerful in general, in that the selecting predicate (the Where clause) can be an arbitrary boolean expression, while the implicit tests in myPatterns/JS queries are (currently) limited to testing sub-values against constants, and testing the "shape" of sub-values (such as the length of a list or the presence of a field in an object).

Fortunately, the strengthes of patterns and LINQ can be combined. For instance, consider a restriction of the above query to the persons whose elder son is over 20. Such a constraint cannot be expressed using JSON patterns, but the concise myPatterns query above can be refined by a JSLINQ Where clause as follows:

new JSLINQ(selectMatching(persons, "{name:{firstname:%f,lastname:%l},children:[{gender:'male',born:%b}|%_]}"))
    .Where(function(s) { return new Date().getFullYear() - s.b >= 20; })
Result:

In conclusion, for some queries over data sequences, myPatterns/JS offers a more concise and declarative form than LINQ. More complex queries can be most conveniently expressed by combining a declarative part expressed as a JSON pattern with further explicit constraints and processing (e.g. sorting) expressed in LINQ. There is thus a strong complementarity between these two technologies.

Keep also in mind that the matching notation in myPatterns/JS is not limited to JSON, but can be easily redefined by customized notations for specific data structures.