January 03, 2013
On Thursday, 3 January 2013 at 00:08:12 UTC, Peter Summerland wrote:
> On Wednesday, 2 January 2013 at 03:52:21 UTC, bearophile wrote:
>> Era Scarecrow:
>>
>>> Well I see that you have opIndexUnary twice; According to the manual you wouldn't need as it would rewrite the code so you only need it once;
>>
>> And as you have seen if you remove the useles opIndexRight the program keeps compiling with no errors and keeps asserting at run-time:
>>
>>
>>
>> struct Foo {
>>    int x;
>>    alias this = x;
>> }
>>
>> class Bar {
>>    Foo[] data;
>>
>>    this() {
>>        data.length = 10;
>>    }
>>
>>    Foo opIndex(uint i) {
>>        return data[i];
>>    }
>>
>>    void opIndexUnary(string op)(uint i) if (op == "++") {
>>        data[i]++;
>>    }
>> }
>>
>> void main() {
>>    auto barfoo = new Bar;
>>    ++barfoo[3];
>>    assert(barfoo.data[3] == 1);
>>    barfoo[3]++;
>>    assert(barfoo.data[3] == 2);
>> }
>>
>>
>> Bye,
>> bearophile
>
> I am really just guessing, but it appears that whatever the post increment op gets rewritten as takes either a reference to or a copy of what is being incremented and it involves opIndex, not opIndexUnary as suggested by TDPL p. 378 and p. 369.

That's a (old) bug. If opIndexUnary is present, then that should be called. However, currently, the compiler doesn't "see" it when it sees "a[i]++".

http://d.puremagic.com/issues/show_bug.cgi?id=5044

"++a[i]" works correctly (AFAIK). If you want to test opUnary, DO NOT toy around with the post increment index version. Just stick to simple unary:
"++a" and "a++"

> If opIndex is changed to return ref Foo, everything works. (I had change alias this = x to alias x this - 2.60 64 bit). Here is code that shows when opIndexUnary and opIndex is called and when the assertion fails for version(B) - with ref and version(A) without ref.

As soon as opIndex returns a ref, then *nothing* of opIndexSomething becomes necessary (heck, it becomes "counter necessary"). Same thing for front. If front returns by ref, then you don't need the "front(T t)" variant.

I don't have TDPL under my eyes right now, but I remember it explicitly stating that these functions where specifically meant to emulate access primitives, for functions that can't ref access to its primitives. In particular, for things like array bool.
January 03, 2013
On Thursday, 3 January 2013 at 07:03:23 UTC, monarch_dodra wrote:
> On Thursday, 3 January 2013 at 00:08:12 UTC, Peter Summerland wrote:
>> On Wednesday, 2 January 2013 at 03:52:21 UTC, bearophile wrote:
>>> Era Scarecrow:
>>>
>>>> Well I see that you have opIndexUnary twice; According to the manual you wouldn't need as it would rewrite the code so you only need it once;
>>>
>>> And as you have seen if you remove the useles opIndexRight the program keeps compiling with no errors and keeps asserting at run-time:
>>>
>>>
>>>
>>> struct Foo {
>>>   int x;
>>>   alias this = x;
>>> }
>>>
>>> class Bar {
>>>   Foo[] data;
>>>
>>>   this() {
>>>       data.length = 10;
>>>   }
>>>
>>>   Foo opIndex(uint i) {
>>>       return data[i];
>>>   }
>>>
>>>   void opIndexUnary(string op)(uint i) if (op == "++") {
>>>       data[i]++;
>>>   }
>>> }
>>>
>>> void main() {
>>>   auto barfoo = new Bar;
>>>   ++barfoo[3];
>>>   assert(barfoo.data[3] == 1);
>>>   barfoo[3]++;
>>>   assert(barfoo.data[3] == 2);
>>> }
>>>
>>>
>>> Bye,
>>> bearophile
>>
>> I am really just guessing, but it appears that whatever the post increment op gets rewritten as takes either a reference to or a copy of what is being incremented and it involves opIndex, not opIndexUnary as suggested by TDPL p. 378 and p. 369.

Thanks for responding.

On rereading, maybe TDPL is just suggesting that the rewrite for a[i]++ should be handled exactly the same as foo++, where foo and a[i] are Foos. I.e., if the result of a[i]++ is not used, rewrite it as ++a[i]. That apparently is not happening, as reported in bug 5044. But if a[i]++ is used, then apply

(ref x){auto t=x; ++x; return t;} to (a[i])

which causes the function to be applied to a copy of a[i], resulting in the nop effect of a[i]++ (unless a[i] returns a ref, and we don't want that). So IMHO using the the general rewrite at p369 for indexed items is incorrect. And base don my probing, I am guessing that the general rewrite is indeed applied to a[i]++.

Would it be possible to have the compiler call opIndexUnary!"<op>"(b1, ...bk) where <op> could be, say, "post++" and "post--" in addition to "++" and "--", when appropriate? Seems like a simple solution.

>
> That's a (old) bug. If opIndexUnary is present, then that should be called. However, currently, the compiler doesn't "see" it when it sees "a[i]++".
>
> http://d.puremagic.com/issues/show_bug.cgi?id=5044
>
> "++a[i]" works correctly (AFAIK). If you want to test opUnary, DO NOT toy around with the post increment index version. Just stick to simple unary:
> "++a" and "a++"

Sorry for the messy example, but I did not mean to test opUnary. In the code, I just wanted to see if the rewrite of a[i]++ was calling it (which it is - in version A and version B).


>
>> If opIndex is changed to return ref Foo, everything works. (I had change alias this = x to alias x this - 2.60 64 bit). Here is code that shows when opIndexUnary and opIndex is called and when the assertion fails for version(B) - with ref and version(A) without ref.
>
> As soon as opIndex returns a ref, then *nothing* of opIndexSomething becomes necessary (heck, it becomes "counter necessary"). Same thing for front. If front returns by ref, then you don't need the "front(T t)" variant.
>
> I don't have TDPL under my eyes right now, but I remember it explicitly stating that these functions where specifically meant to emulate access primitives, for functions that can't ref access to its primitives. In particular, for things like array bool.

1 2
Next ›   Last »