July 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_ 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

July 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:

>

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!

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!

July 15, 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:

>

[...]

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!

July 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

auto x = i[1]++;

Expands to:

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.

July 15, 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.

July 15, 2021

On Thursday, 15 July 2021 at 04:07:49 UTC, Tejas wrote:

>

Your code

auto x = i[1]++;

Expands to:

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:

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:

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.

July 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:

>

Your code

auto x = i[1]++;

Expands to:

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:

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:

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) :

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).

July 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) :

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

(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

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.

July 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:

>

[...]

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

(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

July 16, 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:

>

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

(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.

1 2 3
Next ›   Last »