May 20, 2016
On 05/20/2016 02:50 AM, Manu via Digitalmars-d-announce wrote:
> Ah. Okay, well while this is a very interesting talk, I was indeed
> hoping you were going to make a D concepts proposal... do you have
> such a thing in mind, or are you against concepts in D?

I'm not "against" anything. I think we can improve contracts in many ways before we reach the conclusion that we need an overlapping language feature. I'd rather have one well executed feature rather than two half-done features. -- Andrei
May 20, 2016
On 05/19/2016 06:50 PM, Jens Müller wrote:
> What if you stomped over an index in a that has as an equal index in b
> (it could be anywhere in b).

Hmmm, you're right. So that doesn't work, or at least not efficiently (the fixup would entail a binary search in b).

How about this idea: arrange things such that a.back.idx <= b.back.idx (i.e. swap them if not so). Then stomp b.back.idx with size_t.max. Your kernel is:

if (a[i].idx < b[j].idx) {
  if (i == imax) break; // check needed
  i++;
} else if (a[i].idx > b[j].idx) {
  j++; // no check needed
} else {
  // no check needed
  r += a[i++].val * b[j++].val;
}

The fixup needs only to account for the case a.back.idx == b.back.idx. In fact I like this a lot better than others because it works real fast for identical vector (taking the norm) or similar vectors (often the case). Works?


Andrei

May 20, 2016
On Friday, 20 May 2016 at 14:14:18 UTC, Andrei Alexandrescu wrote:
> On 05/19/2016 06:50 PM, Jens Müller wrote:
>> What if you stomped over an index in a that has as an equal index in b
>> (it could be anywhere in b).
>
> Hmmm, you're right. So that doesn't work, or at least not efficiently (the fixup would entail a binary search in b).
>
> How about this idea: arrange things such that a.back.idx <= b.back.idx (i.e. swap them if not so). Then stomp b.back.idx with size_t.max. Your kernel is:
>
> if (a[i].idx < b[j].idx) {
>   if (i == imax) break; // check needed
>   i++;
> } else if (a[i].idx > b[j].idx) {
>   j++; // no check needed
> } else {
>   // no check needed
>   r += a[i++].val * b[j++].val;
> }
>
> The fixup needs only to account for the case a.back.idx == b.back.idx. In fact I like this a lot better than others because it works real fast for identical vector (taking the norm) or similar vectors (often the case). Works?

No it doesn't work because you need to break in the last case. Consider the case when the last element of a is equal to an element in b. Next iteration you overrun a.
But optimizing for similar vectors is interesting.

Jens
May 20, 2016
On 5/20/2016 6:47 AM, H. S. Teoh via Digitalmars-d-announce wrote:
> Not to mention inconsistency in what exactly
> is being tested for: if you want to check if something is an input
> range, do you use is(typeof(R.empty)), etc., or should you use
> __traits(compiles, R.init.empty), or is it is(typeof((R r){r.empty;})),
> or any of the 15 or so slightly different ways of testing for the
> existence and type of some aggregate member, all subtly different from
> each other? Subtly different as in, for instance, testing for
> is(typeof((){R r; bool x = r.empty;})) is different from is(typeof(R
> r){bool x = r.empty;}), because the former doesn't work with R that has
> parameters closing over a local scope, whereas the latter does.

That is not a problem with constraints, it's a result of a dozen people adding constraints in an uncoordinated manner. I.e. it's a library problem.


> Whereas if D had concepts, it would have been a simple
> matter of defining the prototypical range with struct-like syntax and
> calling it a day.

That really isn't good enough. Constraints can address behavior and relationships, concepts do not.

May 20, 2016
On 5/20/16 2:13 PM, Jens Müller wrote:
> No it doesn't work because you need to break in the last case. Consider
> the case when the last element of a is equal to an element in b. Next
> iteration you overrun a.

I'm not that Bright :o).

So you'd need one more test, but you still save the other test and the test on one of the three branches, so 2 out of 4. -- Andrei
May 20, 2016
On Friday, 20 May 2016 at 20:04:35 UTC, Andrei Alexandrescu wrote:
> On 5/20/16 2:13 PM, Jens Müller wrote:
>> No it doesn't work because you need to break in the last case. Consider
>> the case when the last element of a is equal to an element in b. Next
>> iteration you overrun a.
>
> I'm not that Bright :o).

Me neither.

> So you'd need one more test, but you still save the other test and the test on one of the three branches, so 2 out of 4. --

Yes. Current version reduces it from 4 to 2.
I've read that people use SSE to speed it up. Maybe I consider this later.
If we want to improve on similar vectors (which is a great idea) we just reorder the cases, I'll guess. Just did it. It improves on my test data. But then on near dissimilar input I expect it to be worse.
When doing these optimizations it is always dependent on the expected input which is a pity when optimizing library functions. These must work in all cases and should only be less efficient for very good reason.
I'm looking forward to Fastware.

Jens
May 21, 2016
On 20 May 2016 at 18:26, Walter Bright via Digitalmars-d-announce <digitalmars-d-announce@puremagic.com> wrote:
> On 5/19/2016 11:50 PM, Manu via Digitalmars-d-announce wrote:
>>
>> Ah. Okay, well while this is a very interesting talk, I was indeed hoping you were going to make a D concepts proposal... do you have such a thing in mind, or are you against concepts in D?
>
>
> D has constraints. No point in adding concepts.

I really struggle to agree. Constraints are a good first-step in that direction, but they're unwieldy, produce the worst looking function signatures (read: documentation) of literally any language ever conceived, relatively awkward error feedback, and very quickly get out of hand if you have many variations of possible constraints.
May 21, 2016
On Saturday, 21 May 2016 at 08:45:45 UTC, Manu wrote:
> Constraints are a good first-step in that direction, but they're unwieldy, produce the worst looking function signatures (read: documentation) of literally any language ever conceived, relatively awkward error feedback, and very quickly get out of hand if you have many variations of possible constraints.

Constraints are enough for simple matters.
As soon as they are used to distinguish between many overloads with complicated relationships they become slightly crude.

However this can be worked around with having static ifs and static asserts(0).
I find myself just one variadic template with a lot of static ifs branches.

May 21, 2016
On 05/21/2016 04:45 AM, Manu via Digitalmars-d-announce wrote:
> On 20 May 2016 at 18:26, Walter Bright via Digitalmars-d-announce
> <digitalmars-d-announce@puremagic.com> wrote:
>> On 5/19/2016 11:50 PM, Manu via Digitalmars-d-announce wrote:
>>>
>>> Ah. Okay, well while this is a very interesting talk, I was indeed
>>> hoping you were going to make a D concepts proposal... do you have
>>> such a thing in mind, or are you against concepts in D?
>>
>>
>> D has constraints. No point in adding concepts.
>
> I really struggle to agree. Constraints are a good first-step in that
> direction, but they're unwieldy, produce the worst looking function
> signatures (read: documentation) of literally any language ever
> conceived, relatively awkward error feedback, and very quickly get out
> of hand if you have many variations of possible constraints.

I guess a lot more detail would be necessary here. A bunch of good folks (at least better than me) have worked for over a decade on C++ concepts and three (three!) proposals later it's still unclear whether they're a good idea. -- Andrei
May 21, 2016
On Friday, 20 May 2016 at 19:34:11 UTC, Walter Bright wrote:
> Constraints can address behavior and relationships, concepts do not.

Wow, TIL. That's so clear once said !
There's been several discussion here and even one phobos PR that proposes a kind of concepts but I didn't realize before that the 2 things are different.

The problem I see in D is that the constraints, since they prevent to output a good message, are doing both (in a way):

void foo(T)(T t)
if (constraint)
{
    // cannot have the message if constraint fails...
    static assert((checkConcept!T).ok, (checkConcept!T).message);
}

At the language level it would work

void foo(T)(T t) @Concept(CheckerTemplate) // use this to output a smart message
if (constraint)
{

}

But really, without changing much what I'd like to see is a DMD feature that
would parse and evaluate the constraints to output a message: such as

void foo(T)(T t)
if ((a || b) && (a || b))
{
}

> error:(a || b) is false

instead of throwing the whole constraint text in the output.