A opIndexUnary quiz

Peter Summerland p.summerland at gmail.com
Thu Jan 3 10:08:51 PST 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.



More information about the Digitalmars-d-learn mailing list