www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - opIndexUnary post in-/decrement how to ?

reply wjoe <invalid example.com> writes:
I'm want to do something like this
```D
part_int_t!(1,2,3) i;

auto x = -i[0];
--i[1]; // 1
i[1]++; // 2

```
I think the operator I need to overload would be opIndexUnary 
which I did.
(1) compiles.
(2) doesn't - the compiler complains that i.opIndex isn't an 
lvalue and can't be modified.
The language spec says that Post in- and decrement are rewritten 
but something's fishy.
What's going on behind the scene and how can I make it work?
Jul 14
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 10:07:38 UTC, wjoe wrote:
 I'm want to do something like this
 ```D
 part_int_t!(1,2,3) i;

 auto x = -i[0];
 --i[1]; // 1
 i[1]++; // 2

 ```
 I think the operator I need to overload would be opIndexUnary 
 which I did.
 (1) compiles.
 (2) doesn't - the compiler complains that i.opIndex isn't an 
 lvalue and can't be modified.
 The language spec says that Post in- and decrement are 
 rewritten but something's fishy.
 What's going on behind the scene and how can I make it work?
Please check the language spec here: https://dlang.org/spec/operatoroverloading.html#postincrement_postdecrement_operators You can't directly overload the postincrement operator. You need to rewrite it like: ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;``` Sorry I can't provide something even more concrete.
Jul 14
next sibling parent reply wjoe <invalid example.com> writes:
On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:
 ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;```

 Sorry I can't provide something even more concrete.
Yes I saw that, and I suppose it would work just fine if it were rewritten to just ```++i[1]```. What I'm struggling to understand is the ```{auto a = i[1], ... ,a}``` part. I can't parse that. What's up with the assignment and the comma stuff ?
Jul 14
next sibling parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:
 ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;```

 Sorry I can't provide something even more concrete.
Yes I saw that, and I suppose it would work just fine if it were rewritten to just ```++i[1]```. What I'm struggling to understand is the ```{auto a = i[1], ... ,a}``` part. I can't parse that. What's up with the assignment and the comma stuff ?
I think it's a bug, because the following works: ```d import std.stdio; struct abc{ int[100] a; int opIndex(int index){ return a[index]; } int opIndexUnary(string s)(int index) if(s == "++"){ return ++a[index]; } int[] opUnary(string s)() if (s == "++"){ return a[] += 1; } } void main (){ abc s; int[100] a; int temp; writeln (a[20]++); writeln(a[20]); writeln(++s[20]); writeln(s[20]); //writeln(s[0]++);// doesn't work for some reason writeln(s[0]); writeln(s++);//but this works!! writeln(s); } ```
Jul 14
next sibling parent reply vit <vit vit.vit> writes:
On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:
 ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;```

 Sorry I can't provide something even more concrete.
Yes I saw that, and I suppose it would work just fine if it were rewritten to just ```++i[1]```. What I'm struggling to understand is the ```{auto a = i[1], ... ,a}``` part. I can't parse that. What's up with the assignment and the comma stuff ?
I think it's a bug, because the following works: ```d import std.stdio; struct abc{ int[100] a; int opIndex(int index){ return a[index]; } int opIndexUnary(string s)(int index) if(s == "++"){ return ++a[index]; } int[] opUnary(string s)() if (s == "++"){ return a[] += 1; } } void main (){ abc s; int[100] a; int temp; writeln (a[20]++); writeln(a[20]); writeln(++s[20]); writeln(s[20]); //writeln(s[0]++);// doesn't work for some reason writeln(s[0]); writeln(s++);//but this works!! writeln(s); } ```
From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading.
Jul 14
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 13:09:56 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:
 ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;```

 Sorry I can't provide something even more concrete.
Yes I saw that, and I suppose it would work just fine if it were rewritten to just ```++i[1]```. What I'm struggling to understand is the ```{auto a = i[1], ... ,a}``` part. I can't parse that. What's up with the assignment and the comma stuff ?
I think it's a bug, because the following works: ```d import std.stdio; struct abc{ int[100] a; int opIndex(int index){ return a[index]; } int opIndexUnary(string s)(int index) if(s == "++"){ return ++a[index]; } int[] opUnary(string s)() if (s == "++"){ return a[] += 1; } } void main (){ abc s; int[100] a; int temp; writeln (a[20]++); writeln(a[20]); writeln(++s[20]); writeln(s[20]); //writeln(s[0]++);// doesn't work for some reason writeln(s[0]); writeln(s++);//but this works!! writeln(s); } ```
From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading.
If the rewriting part doesn't work with overloading then why aren't we allowed to explicitly overload ```post-increment/decrement``` operators? How else will the OP solve their problem? It must rewrite, otherwise it's impossible (I think).
Jul 14
parent reply vit <vit vit.vit> writes:
On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 13:09:56 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:
 [...]
From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading.
If the rewriting part doesn't work with overloading then why aren't we allowed to explicitly overload ```post-increment/decrement``` operators? How else will the OP solve their problem? It must rewrite, otherwise it's impossible (I think).
This work: ```d import std.stdio; struct abc{ int[100] a; ref int opIndex(int index)return{ return a[index]; } } void main (){ abc s; s[0]++; ++s[0]; } ```
Jul 14
next sibling parent reply wjoe <invalid example.com> writes:
On Wednesday, 14 July 2021 at 14:39:03 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 13:09:56 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:
 [...]
From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading.
If the rewriting part doesn't work with overloading then why aren't we allowed to explicitly overload ```post-increment/decrement``` operators? How else will the OP solve their problem? It must rewrite, otherwise it's impossible (I think).
This work: ```d import std.stdio; struct abc{ int[100] a; ref int opIndex(int index)return{ return a[index]; } } void main (){ abc s; s[0]++; ++s[0]; } ```
This does work for that example but I can't return by reference because what I'm operating on is a part of an int. Some context: ```D struct part_int_t(ARGS...) { int _int; mixin(generate_parts!ARGS); } alias handle_t = part_int_t!("isAllocated", 1, "gen", 8, "index", 23); handle_t handle; static assert (is(handle.typeof_isAllocated): bool)); static assert (is(handle.typeof_gen): ubyte)); static assert (is(handle.typeof_index): uint)); handle[2] = true; handle.gen = 1; handle.index = 1234; assert (handle.isAllocated); assert (handle.gen = 1); assert (handle[0] = 1234); handle++; assert (handle.index == 1235); handle.gen++; assert (handle.gen == 2); handle.reset(); assert (!handle.isAllocated); assert (handle.gen = 3); assert (handle.index = 0); ``` generate_parts!ARGS produces bit masks, getters, setters, opIndex/OpAssign/Unary, etc. and it's impossible to return bits 0-26 of _int by ref.
Jul 14
parent reply vit <vit vit.vit> writes:
On Wednesday, 14 July 2021 at 15:01:45 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 14:39:03 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote:
 [...]
This work: ```d import std.stdio; struct abc{ int[100] a; ref int opIndex(int index)return{ return a[index]; } } void main (){ abc s; s[0]++; ++s[0]; } ```
This does work for that example but I can't return by reference because what I'm operating on is a part of an int. Some context: ```D struct part_int_t(ARGS...) { int _int; mixin(generate_parts!ARGS); } alias handle_t = part_int_t!("isAllocated", 1, "gen", 8, "index", 23); handle_t handle; static assert (is(handle.typeof_isAllocated): bool)); static assert (is(handle.typeof_gen): ubyte)); static assert (is(handle.typeof_index): uint)); handle[2] = true; handle.gen = 1; handle.index = 1234; assert (handle.isAllocated); assert (handle.gen = 1); assert (handle[0] = 1234); handle++; assert (handle.index == 1235); handle.gen++; assert (handle.gen == 2); handle.reset(); assert (!handle.isAllocated); assert (handle.gen = 3); assert (handle.index = 0); ``` generate_parts!ARGS produces bit masks, getters, setters, opIndex/OpAssign/Unary, etc. and it's impossible to return bits 0-26 of _int by ref.
Try something like this: ```d import std.stdio; struct abc{ int[100] a; struct Proxy{ abc* ptr; const int index; int opUnary(string op : "++")(){ return ptr.a[index]; } } Proxy opIndex(int index)return{ return Proxy(&this, index); } } void main (){ abc s; s[0]++; ++s[0]; } ```
Jul 14
parent reply vit <vit vit.vit> writes:
On Wednesday, 14 July 2021 at 15:19:03 UTC, vit wrote:


```d
import   std.stdio;

struct abc{
     int[100] a;

     struct Proxy{
         abc* ptr;
     	const int index;

         int opUnary(string op : "++")(){
         	return ++ptr.a[index];     //add missing ++
         }
     }

     Proxy opIndex(int index)return{
         return Proxy(&this, index);
     }
}

void main (){
     abc s;
     s[0]++;
     ++s[0];
}


```
Jul 14
next sibling parent Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 15:23:05 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 15:19:03 UTC, vit wrote:


 ```d
 import   std.stdio;

 struct abc{
     int[100] a;

     struct Proxy{
         abc* ptr;
     	const int index;

         int opUnary(string op : "++")(){
         	return ++ptr.a[index];     //add missing ++
         }
     }

     Proxy opIndex(int index)return{
         return Proxy(&this, index);
     }
 }

 void main (){
     abc s;
     s[0]++;
     ++s[0];
 }


 ```
The ```post increment``` still doesn't work :( this is the output for your code: ``` Proxy(7FFC7ACB3E60, 0) 2 ``` And if the add the following statements: ```d writeln(s[0]++); writeln(s[0]); writeln(s[0]++); writeln(s[0]); writeln(++s[0]); ``` Output: ``` Proxy(7FFCBE3CAF20, 0) Proxy(7FFCBE3CAF20, 0) Proxy(7FFCBE3CAF20, 0) Proxy(7FFCBE3CAF20, 0) 3 ```
Jul 14
prev sibling parent Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 15:23:05 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 15:19:03 UTC, vit wrote:


 ```d
 import   std.stdio;

 struct abc{
     int[100] a;

     struct Proxy{
         abc* ptr;
     	const int index;

         int opUnary(string op : "++")(){
         	return ++ptr.a[index];     //add missing ++
         }
     }

     Proxy opIndex(int index)return{
         return Proxy(&this, index);
     }
 }

 void main (){
     abc s;
     s[0]++;
     ++s[0];
 }


 ```
I tried changing ```s[0]++``` to ``` s[0] += 1``` the same lvalue problem arose :( ``` Error: `s.opIndex(0)` is not an lvalue and cannot be modified ```
Jul 14
prev sibling parent Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 14:39:03 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 13:09:56 UTC, vit wrote:
 On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:
 [...]
From doc: https://dlang.org/spec/operatoroverloading.html Postincrement e++ and Postdecrement e-- Operators These are not directly overloadable, but instead are rewritten in terms of the ++e and --e prefix operators: Postfix Operator Rewrites op rewrite e-- (auto t = e, --e, t) e++ (auto t = e, ++e, t) Rewriting part doesn't work with operator overloading.
If the rewriting part doesn't work with over
This work: ```d import std.stdio; struct abc{ int[100] a; ref int opIndex(int index)return{ return a[index]; } } void main (){ abc s; s[0]++; ++s[0]; } ```
Oh... since it was asking for an lvalue, you just passed it by reference... seems so obvious in hindsight... Nice. Pity it doesn't seem to solve OP's problem.
Jul 14
prev sibling parent wjoe <invalid example.com> writes:
On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:
 I think it's a bug, because the following works:

 ```d

 import   std.stdio;

 struct abc{
     int[100] a;
     int opIndex(int index){
         return a[index];
     }
     int opIndexUnary(string s)(int index)
         if(s == "++"){
         return ++a[index];
         }
     int[] opUnary(string s)() if (s == "++"){
         return a[] += 1;
     }
 }

 void main (){
     abc s;
     int[100] a;
     int temp;
     writeln (a[20]++);

     writeln(a[20]);

     writeln(++s[20]);

     writeln(s[20]);

     //writeln(s[0]++);// doesn't work for some reason

     writeln(s[0]);

     writeln(s++);//but this works!!

     writeln(s);
 }

 ```
```D writeln(++s[0]); // should work writeln(s++); // this calls opUnary if I'm not mistaken ```
Jul 14
prev sibling parent reply Mike Parker <aldacron gmail.com> writes:
On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:
 ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;```

 Sorry I can't provide something even more concrete.
Yes I saw that, and I suppose it would work just fine if it were rewritten to just ```++i[1]```. What I'm struggling to understand is the ```{auto a = i[1], ... ,a}``` part. I can't parse that. What's up with the assignment and the comma stuff ?
It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. ```d int i = 1; assert(++i == 2); int j = 1; assert(j++ == 1); ``` The rewrite of the compiler is done in such a way that the result of the expression is the original value. That's what the commas are for. ``` So you can parse that rewrite example as it if were a function, with each expression separated by a comma, and the final expression the result: ```d int postInc(ref int j) { auto a = j; ++j; return a; } ``` It doesn't actually create a function, but this demonstrates the effect. So that's why you don't have to worry about postfix/prefix for these. The compiler handles that behind the scenes. All you need to worry about is returning the incremented value.
Jul 14
parent reply wjoe <invalid example.com> writes:
On Wednesday, 14 July 2021 at 14:50:01 UTC, Mike Parker wrote:
 On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 [...]
It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. [...]
That makes a lot of sense now, thank you!
Jul 14
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 15:08:56 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 14:50:01 UTC, Mike Parker wrote:
 On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 [...]
It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. [...]
That makes a lot of sense now, thank you!
**IT WORKS NOW** Thanks vit for the ```ref``` idea! ```d import std.stdio; struct abc{ int[100] a; static int temp; ref/*notice this ref*/ int opIndex(int index)return/*NOTICE THE RETURN*/ { return a[index]; } int opIndexUnary(string s)(int index) if(s == "++"){ return ++a[index]; } int[] opUnary(string s)() if (s == "++"){ return a[] += 1; } } void main (){ abc s; writeln(s[0]++);// doesn't work for some reason EDIT: IT NOW WORKS!!!!!!!! writeln(s[0]); writeln(++s[0]); // writeln(s++);//but this works!! // writeln(s); } ```
Jul 14
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 7/14/21 9:13 AM, Tejas wrote:

      ref/*notice this ref*/ int opIndex(int index)return/*NOTICE THE
 RETURN*/ {
Indeed... I cover that 'ref' here: http://ddili.org/ders/d.en/operator_overloading.html#ix_operator_overloading.return%20type,%20operator Two quotes from that section: 1) "it is advisable to observe the return type of the same operator on fundamental types." NOTE: I agree that for that to make sense, one needs to know the "return type" of fundamental type operations. It may not be clear that ++i is a reference to 'i' ("i itself"): void main() { int i; ++i = 42; assert(i == 42); } 2) "With the exception of opAssign, it is recommended that the operators that modify the object return the object itself. [...] The return type is the type of the struct, marked by the ref keyword to mean reference." Ali
Jul 14
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 17:42:03 UTC, Ali Çehreli wrote:
 On 7/14/21 9:13 AM, Tejas wrote:

      ref/*notice this ref*/ int opIndex(int
index)return/*NOTICE THE
 RETURN*/ {
Indeed... I cover that 'ref' here: http://ddili.org/ders/d.en/operator_overloading.html#ix_operator_overloading.return%20type,%20operator Two quotes from that section: 1) "it is advisable to observe the return type of the same operator on fundamental types." NOTE: I agree that for that to make sense, one needs to know the "return type" of fundamental type operations. It may not be clear that ++i is a reference to 'i' ("i itself"): void main() { int i; ++i = 42; assert(i == 42); } 2) "With the exception of opAssign, it is recommended that the operators that modify the object return the object itself. [...] The return type is the type of the struct, marked by the ref keyword to mean reference." Ali
To be honest even the compiler error should have been a dead giveaway that opIndex was returning a _constant_ value and the ```++``` operator can't operate on that... I should've taken the diagnostic to heart and not just tried to brute force my way through the problem. Obviously, I retract my statement that this might be a compiler bug.
Jul 14
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 7/14/21 11:27 AM, Tejas wrote:

 the compiler error should have been a dead giveaway
 that opIndex was returning a _constant_ value
I know you mean "rvalue" but if I may be unnecessarily pedantic, an rvalue can indeed be mutated: struct A { int i; void mutate() { i = 42; import std.stdio; writeln("I am not constant. :)"); } } struct B { auto opUnary(string op)() { return A(); } } void main() { auto b = B(); (++b).mutate(); // <-- Mutating an rvalue } Ali
Jul 14
prev sibling parent reply wjoe <invalid example.com> writes:
On Wednesday, 14 July 2021 at 16:13:35 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 15:08:56 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 14:50:01 UTC, Mike Parker wrote:
 On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:
 [...]
It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. [...]
That makes a lot of sense now, thank you!
**IT WORKS NOW** Thanks vit for the ```ref``` idea! ```d import std.stdio; struct abc{ int[100] a; static int temp; ref/*notice this ref*/ int opIndex(int index)return/*NOTICE THE RETURN*/ { return a[index]; } int opIndexUnary(string s)(int index) if(s == "++"){ return ++a[index]; } int[] opUnary(string s)() if (s == "++"){ return a[] += 1; } } void main (){ abc s; writeln(s[0]++);// doesn't work for some reason EDIT: IT NOW WORKS!!!!!!!! writeln(s[0]); writeln(++s[0]); // writeln(s++);//but this works!! // writeln(s); } ```
Congratulations:) Unfortunately I haven't got anything I could return by ref so I can't take advantage of a low hanging fruit. In my book overloading operators is no fun - at all - and always a last resort because it requires so much time and testing and causes so many headaches. Workarounds exist like ```i[n] += 1``` or direct call via ```i.opIndexUnary!"++"(n)``` or simply ```++i[n]```. But that's beside the point. There's nothing in the spec that says something about something needs to be returned by ref. Rewriting manually compiles and works as intended. So clearly something else is going on which makes the compiler select ```opIndex``` over ```opIndexUnary``` rewriting it post to pre. In my particular case the compiler can rule out ```opIndex``` so why does it abort instead of trying ```opIndexUnary``` ? Or was it trying and it didn't work ? If that's the case I'd like to know the reason why it discarded ```opIndexUnary```. Anyways all the answers so far are much appreciated!
Jul 14
next sibling parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 20:55:32 UTC, wjoe wrote:
 On Wednesday, 14 July 2021 at 16:13:35 UTC, Tejas wrote:
 [...]
Congratulations:) Unfortunately I haven't got anything I could return by ref so I can't take advantage of a low hanging fruit. In my book overloading operators is no fun - at all - and always a last resort because it requires so much time and testing and causes so many headaches. Workarounds exist like ```i[n] += 1``` or direct call via ```i.opIndexUnary!"++"(n)``` or simply ```++i[n]```. But that's beside the point. There's nothing in the spec that says something about something needs to be returned by ref. Rewriting manually compiles and works as intended. So clearly something else is going on which makes the compiler select ```opIndex``` over ```opIndexUnary``` rewriting it post to pre. In my particular case the compiler can rule out ```opIndex``` so why does it abort instead of trying ```opIndexUnary``` ? Or was it trying and it didn't work ? If that's the case I'd like to know the reason why it discarded ```opIndexUnary```. Anyways all the answers so far are much appreciated!
I'm so sorry all this was basically useless for you. I can't spend more time on this, so as a last resort I leave you this: https://dlang.org/phobos/std_bitmanip.html This is the official bit manipulation standard library, maybe it will help you in some way; the ```bitfield``` struct looked mighty familiar to your ```part_int``` struct, but maybe that's my cognitive bias, you should verify it. Best of luck!
Jul 14
parent wjoe <invalid example.com> writes:
On Thursday, 15 July 2021 at 04:01:15 UTC, Tejas wrote:
 I'm so sorry all this was basically useless for you.

 I can't spend more time on this, so as a last resort I leave 
 you this:

 https://dlang.org/phobos/std_bitmanip.html

 This is the official bit manipulation standard library, maybe 
 it will help you in some way; the ```bitfield``` struct looked 
 mighty familiar to your ```part_int``` struct, but maybe that's 
 my cognitive bias,  you should verify it.

 Best of luck!
Oh no it wasn't useless at all. The time and effort you put into this is very much appreciated and that of everyone else, too.
Jul 15
prev sibling parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 20:55:32 UTC, wjoe wrote:

 In my particular case the compiler can rule out ```opIndex``` 
 so why does it abort instead of trying ```opIndexUnary``` ? Or 
 was it trying and it didn't work ? If that's the case I'd like 
 to know the reason why it discarded ```opIndexUnary```.

 Anyways all the answers so far are much appreciated!
Your code ```d auto x = i[1]++; ``` Expands to: ```d auto x = (auto e = i[1]/*notice opIndex*/, ++i[1]/* notice opIndexUnary*/, return e;); ``` This doesn't happen with pre increment. No compiler shenanigans. Hence your problems. Please take a look at the library I mentioned previously, it may help.
Jul 14
parent reply wjoe <invalid example.com> writes:
On Thursday, 15 July 2021 at 04:07:49 UTC, Tejas wrote:
 Your code
 ```d
 auto x = i[1]++;
 ```
 Expands to:
 ```d
 auto x = (auto e = i[1]/*notice opIndex*/, ++i[1]/* notice 
 opIndexUnary*/, return e;);
 ```

 This doesn't happen with pre increment. No compiler shenanigans.
Interesting to see it spelt out like this (your remarks are very enlightening) so I just went one step further and rewrote this line like so: ```D i[1] = 3; auto x = (){auto e = i[1]; ++i[1]; return e;}(); assert (i[1] == 4 && x == 3); ``` This just works. But I don't think this is what happens. What I think happens is that the compiler rewrites ```i[1]++`` to something like this: ```D i.opIndex(1).opUnary!"++"(); ``` plus all the other shenanigans. I did indeed override opIndex() but since i need to apply a bit mask and do some shifting I can't return anything by ref.
Jul 15
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 15 July 2021 at 11:02:17 UTC, wjoe wrote:
 On Thursday, 15 July 2021 at 04:07:49 UTC, Tejas wrote:
 Your code
 ```d
 auto x = i[1]++;
 ```
 Expands to:
 ```d
 auto x = (auto e = i[1]/*notice opIndex*/, ++i[1]/* notice 
 opIndexUnary*/, return e;);
 ```

 This doesn't happen with pre increment. No compiler 
 shenanigans.
Interesting to see it spelt out like this (your remarks are very enlightening) so I just went one step further and rewrote this line like so: ```D i[1] = 3; auto x = (){auto e = i[1]; ++i[1]; return e;}(); assert (i[1] == 4 && x == 3); ``` This just works. But I don't think this is what happens. What I think happens is that the compiler rewrites ```i[1]++`` to something like this: ```D i.opIndex(1).opUnary!"++"(); ``` plus all the other shenanigans.
Oh yes, that is what happens. I was trying to be a little concise. You are correct, this is what the code will look in the gory details (I believe) : ```d auto x = (auto e = i.opIndex(1), i.opIndexUnary("++")(1)/*this may or may not expand to what you wrote, not sure what the compiler does, although what you say does sound like the obvious thing to do*/, return e); ```
 I did indeed override opIndex() but since i need to apply a bit 
 mask and do some shifting I can't return anything by ref.
As I mentioned, maybe the bit manipulation library could help(although they don't seem to be overloading the operators in the first place, thus sidestepping the problem you encountered).
Jul 15
parent reply wjoe <invalid example.com> writes:
On Thursday, 15 July 2021 at 12:09:20 UTC, Tejas wrote:
 [...]

 Oh yes, that is what happens. I was trying to be a little 
 concise.
 You are correct, this is what the code will look in the gory 
 details (I believe) :
 ```d
 auto x = (auto e = i.opIndex(1), i.opIndexUnary("++")(1)/*this 
 may or may not expand to what you wrote, not sure what the 
 compiler does, although what you say does sound like the 
 obvious thing to do*/, return e);
 ```
 I did indeed override opIndex() but since i need to apply a 
 bit mask and do some shifting I can't return anything by ref.
As I mentioned, maybe the bit manipulation library could help(although they don't seem to be overloading the operators in the first place, thus sidestepping the problem you encountered).
The only way, for me, to explain the error message ```opIndex isn't an lvalue and can't be modified.``` for ```i[1]++``` is that the compiler rewrites to ```D (auto e = i.opIndex(1), i.opIndex(1).opUnary!"++"()/*1) note: not opIndexUnary*/, return e;) ``` If it were using ```opIndexUnary``` at 1) it would work. The gist of it ```D part_int_t!("alpha", 1, "beta", 4, "gamma", 16) a; struct part_int_t(ARGS...) { int _int; mixin(generatePartInt!ARGS); } // auto-generated from ARGS alias typeof_alpha = bool; enum ulong offset_alpha = 0; enum ulong mask_alpha = 0xFFFF; // etc. //getter property const pure nothrow nogc typeof_alpha alpha() { if (_int & signmask_alpha) return cast(typeof(return))(((_int & mask_alpha) >> offset_alpha) | signpad_alpha); else return cast(typeof(return))((_int & mask_alpha) >> offset_alpha); } // setter // ... const pure nothrow nogc auto opIndex(size_t _i) { switch (_i) { default: assert (0, "Out of bounds."); // cases are auto generated from ARGS and mixed in like this case 0: return alpha; case 1: return beta; case 2: return gamma; }} // OpIndexAssign, etc. pure nothrow nogc auto opIndexUnary(string op)(size_t _i) { switch (_i) { default: assert (0, "Out of bounds."); // cases are auto generated from ARGS and mixed in like this case 0: typeof_alpha result; auto tmp = prepare_for_op!(op, "alpha"); mixin(op ~ "tmp"); result = finalize!(op, "alpha")(tmp); return result; // ... }} // repeat for beta and gamma ``` I'll revisit the bitfields in std.bitmanip but there were shortcomings which prompted me to start ```part_int_t```.
Jul 15
parent reply Tejas <notrealemail gmail.com> writes:
On Thursday, 15 July 2021 at 13:28:19 UTC, wjoe wrote:
 On Thursday, 15 July 2021 at 12:09:20 UTC, Tejas wrote:
 [...]
The only way, for me, to explain the error message ```opIndex isn't an lvalue and can't be modified.``` for ```i[1]++``` is that the compiler rewrites to ```D (auto e = i.opIndex(1), i.opIndex(1).opUnary!"++"()/*1) note: not opIndexUnary*/, return e;) ``` If it were using ```opIndexUnary``` at 1) it would work. [...]
Sucks :( I really can't spend more time on this, hope things work out for you somehow. Best of luck Regards Tejas
Jul 15
parent wjoe <invalid example.com> writes:
On Thursday, 15 July 2021 at 15:39:59 UTC, Tejas wrote:
 On Thursday, 15 July 2021 at 13:28:19 UTC, wjoe wrote:
 On Thursday, 15 July 2021 at 12:09:20 UTC, Tejas wrote:
 [...]
The only way, for me, to explain the error message ```opIndex isn't an lvalue and can't be modified.``` for ```i[1]++``` is that the compiler rewrites to ```D (auto e = i.opIndex(1), i.opIndex(1).opUnary!"++"()/*1) note: not opIndexUnary*/, return e;) ``` If it were using ```opIndexUnary``` at 1) it would work. [...]
Sucks :( I really can't spend more time on this, hope things work out for you somehow. Best of luck Regards Tejas
No worries. Your time is very much appreciated.
Jul 16
prev sibling parent Tejas <notrealemail gmail.com> writes:
On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:
 On Wednesday, 14 July 2021 at 10:07:38 UTC, wjoe wrote:
 I'm want to do something like this
 ```D
 part_int_t!(1,2,3) i;

 auto x = -i[0];
 --i[1]; // 1
 i[1]++; // 2

 ```
 I think the operator I need to overload would be opIndexUnary 
 which I did.
 (1) compiles.
 (2) doesn't - the compiler complains that i.opIndex isn't an 
 lvalue and can't be modified.
 The language spec says that Post in- and decrement are 
 rewritten but something's fishy.
 What's going on behind the scene and how can I make it work?
Please check the language spec here: https://dlang.org/spec/operatoroverloading.html#postincrement_postdecrement_operators You can't directly overload the postincrement operator. You need to rewrite it like: ``` {auto a = i[1] , ++i[1] , a} //note the , not the ;``` Sorry I can't provide something even more concrete.
Ignore this, I wanted to say that this is what the _compiler_ rewrites it to when _you_ write ```i[1]++``` There is no way to explicitly overload the ```post increment``` operator because of this.
Jul 14