September 13, 2015
On 09/13/2015 11:00 AM, Sönke Ludwig wrote:
> I had played around with some ideas for a similar project, but didn't
> find a really satisfying solution:
> https://github.com/rejectedsoftware/dotter/blob/11ec72325e76c3329a58545526940c1df5328a2d/source/dotter/orm.d#L320

Yeah, that doesn't look too nice.

I think db.get!Author.where!(a => a.books.count > 10) is very powerful b/c you can easily use relations for querying.

struct Author
{
  @hasMany // relation in SQL or nested in MongoDB
  Book[] books;
}
September 13, 2015
On 09/13/2015 05:03 AM, Andrei Alexandrescu wrote:
> Yah, understood. Problem here is the approach is bound to run into walls at every few steps. Say you fix the comparisons to work. Then you have operators such as LIKE that are necessary yet not representable in D. So more tricks are in order. This is what I've seen with ET in C++ - an endless collection of tricks to achieve modest outcomes at enormous costs.

But this is not an argument to rule out `opBinary!"<"`.

To summarize the arguments.

- logical indexing x[x < 20]

  e.g. opBinary!"<" returns a bit mask to select entries of a large vector

- faster comparison

  struct Foo
  {
      size_t id;
      int opCmp(Foo rhs)
      {
          if (id < rhs.id) return -1;
          if (id == rhs.id) return 0;
          else return 1;
      }
      bool opBinary(string s:"<")(Foo rhs)
      {
          return id < rhs.id;
      }
  }

  Sorting a million Foos w/ random ids is 37.5% slower with opCmp.

  foos.sort!((a, b) => a.opBinary!"<"(b))(); // 104ms
  foos.sort!((a, b) => a < b)(); // 143ms

- expression templates

  I'm well aware of the limitations, but still think it will work out
nicely for an ORM b/c there is precedence in other language, e.g. Rails'
(ActiveRecord) query syntax.

- language regularization

  It's surprising to find these "arbitrary" language limitations.
  The non-predictability of what's possible has always been a huge issue
for me with C++, i.e. you come up with an idea, spend 4 hours
implementing it only to find out that the small detail x isn't feasible.
September 13, 2015
On 09/13/2015 03:15 PM, Jack Stouffer wrote:
> 
> I know that this effect is much harder to create in a explicitly and strongly typed language, but I just wanted to show a real world example of how these could be used to great effect.

But it is doable in D, and even better it's possible to optimize the queries b/c we can know in advance what fields are used. http://dpaste.dzfl.pl/cd375ac594cf
September 13, 2015
On Sunday, 13 September 2015 at 14:06:46 UTC, Martin Nowak wrote:
> - logical indexing x[x < 20]
>
>   e.g. opBinary!"<" returns a bit mask to select entries of a large vector

Oh yes please! This is one of the more powerful features of numpy.

September 13, 2015
On Sunday, 13 September 2015 at 14:06:46 UTC, Martin Nowak wrote:
>   struct Foo
>   {
>       size_t id;
>       int opCmp(Foo rhs)
>       {
>           if (id < rhs.id) return -1;
>           if (id == rhs.id) return 0;
>           else return 1;
>       }
>       bool opBinary(string s:"<")(Foo rhs)
>       {
>           return id < rhs.id;
>       }
>   }
>
>   Sorting a million Foos w/ random ids is 37.5% slower with opCmp.
>

Could you try this?

int opCmp(Foo rhs)
{
  return (id > rhs.id) - (id < rhs.id);
}

September 13, 2015
On 09/13/2015 07:16 PM, Daniel N wrote:
> 
> Could you try this?
> 
> int opCmp(Foo rhs)
> {
>   return (id > rhs.id) - (id < rhs.id);
> }

That's not the point, opCmp requires twice as many comparisons as needed for <. If they are more expansive, e.g. string comparison, your trick won't work.
September 14, 2015
On Sunday, 13 September 2015 at 17:16:40 UTC, Daniel N wrote:
> int opCmp(Foo rhs)
> {
>   return (id > rhs.id) - (id < rhs.id);
> }

IMO, subtracting boolean values is bad code style, it's better to be explicit about your intention:
> (id > rhs.id ? 1 : 0) - (id < rhs.id ? 1 : 0)
September 14, 2015
On Friday, 11 September 2015 at 19:41:41 UTC, Martin Nowak wrote:
> Does anyone have a different idea how to make a nice query language? db.get!Person.where!(p => p.age > 21 && p.name == "Peter")

In our last project we took the following approach:

`auto q = query.builder!Person.age!">"(20).name("Peter");`

In the query-builders there was a lot of ugly concatenating sql stuff. But there was just one guy writing that, everybody else was using the high-level functions.

It allows for a lot of checking, not only on types but also on logic (e.g. age!">"(20).age!"<"(10) was caught at runtime). Plus, very unittestable.

It worked so well that once the query-builders were written, all the constraints, sorting and ordering parameters could be passed straight from the http api down to the query-builders.

Still, you would have to write the query-builders for each Object you want query, although that is something you could do in a DSL.
September 14, 2015
On Friday, 11 September 2015 at 19:41:41 UTC, Martin Nowak wrote:
> AFAIK expression templates are the primary choice tom implement SIMD and
> matrix libraries.
> And I still have [this idea](http://dpaste.dzfl.pl/cd375ac594cf) of
> implementing a nice query language for ORMs.

While expression templates are used in many matrix libraries, there has also been some move away from them. Blaze uses so-called smart expression templates because of what they view as performance limitations of expression templates. I think the general idea is to reduce the creation of temporaries and ordering the calculations so as to minimize the size of the problem (like in the multiplication A*B*c, doing A*(B*c) instead of (A*B)*c)
http://arxiv.org/pdf/1104.1729.pdf

> At least the comparison operators are really limiting, e.g. it's not possible to efficiently implement logical indexing.
>
> vec[vec < 15], vec[vec == 15], vec[(vec != 15) & (vec > 10)]
>

I loves the logical indexing.


September 14, 2015
On 09/14/2015 03:47 PM, Sebastiaan Koppe wrote:
> 
> In our last project we took the following approach:
> 
> `auto q = query.builder!Person.age!">"(20).name("Peter");`

Interesting idea.