digitalmars.D.learn - opIndexUnary post in-/decrement how to ?
- wjoe (15/15) Jul 14 2021 I'm want to do something like this
- Tejas (7/22) Jul 14 2021 Please check the language spec here:
- wjoe (6/8) Jul 14 2021 Yes I saw that, and I suppose it would work just fine if it were
- Tejas (31/41) Jul 14 2021 I think it's a bug, because the following works:
- vit (10/52) Jul 14 2021 From doc: https://dlang.org/spec/operatoroverloading.html
- Tejas (6/71) Jul 14 2021 If the rewriting part doesn't work with overloading then why
- wjoe (5/35) Jul 14 2021 ```D
- Mike Parker (29/39) Jul 14 2021 It's how the contract of post-inc/dec work---pre-inc/dec return
- wjoe (2/7) Jul 14 2021 That makes a lot of sense now, thank you!
- Tejas (30/40) Jul 14 2021 **IT WORKS NOW**
- =?UTF-8?Q?Ali_=c3=87ehreli?= (19/21) Jul 14 2021 Indeed... I cover that 'ref' here:
- Tejas (8/30) Jul 14 2021 To be honest even the compiler error should have been a dead
- =?UTF-8?Q?Ali_=c3=87ehreli?= (21/23) Jul 14 2021 I know you mean "rvalue" but if I may be unnecessarily pedantic, an
- wjoe (18/59) Jul 14 2021 Congratulations:) Unfortunately I haven't got anything I could
- Tejas (5/29) Jul 14 2021 Ignore this, I wanted to say that this is what the _compiler_
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 2021
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 2021
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 2021
On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:On Wednesday, 14 July 2021 at 11:31:36 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); } `````` {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 2021
On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe 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.On Wednesday, 14 July 2021 at 11:31:36 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); } `````` {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 2021
On Wednesday, 14 July 2021 at 13:09:56 UTC, vit wrote:On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote: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).On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe 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.On Wednesday, 14 July 2021 at 11:31:36 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); } `````` {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 2021
On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote:On Wednesday, 14 July 2021 at 13:09:56 UTC, vit 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]; } ```On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote: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).[...]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 2021
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 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.On Wednesday, 14 July 2021 at 13:09:56 UTC, vit 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]; } ```On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote: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).[...]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 2021
On Wednesday, 14 July 2021 at 15:01:45 UTC, wjoe wrote:On Wednesday, 14 July 2021 at 14:39:03 UTC, vit wrote: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]; } ```On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote: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.[...]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 2021
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 2021
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 2021
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 2021
On Wednesday, 14 July 2021 at 14:39:03 UTC, vit wrote:On Wednesday, 14 July 2021 at 13:16:49 UTC, Tejas wrote: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.On Wednesday, 14 July 2021 at 13:09:56 UTC, vit 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]; } ```On Wednesday, 14 July 2021 at 12:49:58 UTC, Tejas wrote:If the rewriting part doesn't work with over[...]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 2021
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 2021
On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas 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. ```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.``` {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 2021
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:That makes a lot of sense now, thank you![...]It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. [...]
Jul 14 2021
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:**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); } ```On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:That makes a lot of sense now, thank you![...]It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. [...]
Jul 14 2021
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 2021
On Wednesday, 14 July 2021 at 17:42:03 UTC, Ali Çehreli wrote:On 7/14/21 9:13 AM, Tejas wrote: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.ref/*notice this ref*/ int opIndex(intindex)return/*NOTICE THERETURN*/ {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 2021
On 7/14/21 11:27 AM, Tejas wrote:the compiler error should have been a dead giveaway that opIndex was returning a _constant_ valueI 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 2021
On Wednesday, 14 July 2021 at 16:13:35 UTC, Tejas wrote:On Wednesday, 14 July 2021 at 15:08:56 UTC, wjoe 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!On Wednesday, 14 July 2021 at 14:50:01 UTC, Mike Parker wrote:**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); } ```On Wednesday, 14 July 2021 at 12:35:07 UTC, wjoe wrote:That makes a lot of sense now, thank you![...]It's how the contract of post-inc/dec work---pre-inc/dec return the modified value, post-inc/dec return the original value. [...]
Jul 14 2021
On Wednesday, 14 July 2021 at 20:55:32 UTC, wjoe wrote:On Wednesday, 14 July 2021 at 16:13:35 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![...]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 2021
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 2021
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 2021
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 2021
On Thursday, 15 July 2021 at 11:02:17 UTC, wjoe wrote:On Thursday, 15 July 2021 at 04:07:49 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); ```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.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 2021
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); ```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```.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 2021
On Thursday, 15 July 2021 at 13:28:19 UTC, wjoe wrote:On Thursday, 15 July 2021 at 12:09:20 UTC, Tejas wrote:Sucks :( I really can't spend more time on this, hope things work out for you somehow. Best of luck Regards Tejas[...]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. [...]
Jul 15 2021
On Thursday, 15 July 2021 at 15:39:59 UTC, Tejas wrote:On Thursday, 15 July 2021 at 13:28:19 UTC, wjoe wrote:No worries. Your time is very much appreciated.On Thursday, 15 July 2021 at 12:09:20 UTC, Tejas wrote:Sucks :( I really can't spend more time on this, hope things work out for you somehow. Best of luck Regards Tejas[...]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. [...]
Jul 16 2021
On Wednesday, 14 July 2021 at 11:31:36 UTC, Tejas wrote:On Wednesday, 14 July 2021 at 10:07:38 UTC, wjoe wrote: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.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 2021