Thread overview
Is there a way to return an lvalue and also an rvalue from the same member function?
Sep 20, 2020
realhet
Sep 20, 2020
realhet
Sep 20, 2020
realhet
Sep 20, 2020
realhet
Sep 20, 2020
realhet
Sep 20, 2020
realhet
September 20, 2020
Hi,

struct S{
  int[2] array;

  ref  x()       { return array[0]; }
  auto x() const { return array[0]; }
}

If there a way to write the function 'x' into one function, not 2 overloads.

I tried auto/const/ref mindlessly :D, also remembered 'inout', but obviously those weren't solve the problem.

(This is going to be a swizzling 'system' that mimics GLSL, later I will make a template that takes 'x'as a template parameter, just wondering that the support for const and non-cons can be done easier.)
September 20, 2020
On Sunday, 20 September 2020 at 13:30:36 UTC, realhet wrote:
> Hi,

More specifically:

struct S{
    int[2] array;

    ref swizzle(string code)(){
             static if(code=="x") return array[0];
        else static if(code=="y") return array[1];
        else static assert("Unhandled");
    }
}

To make this work for const/immutable structs, I have to make another function with the header: auto swizzle(string code)() const{ copy or mixin the whole thing again... }

Maybe there is a language feature for this, like "auto ref" or "inout"?

Thank you!
September 20, 2020
On 9/20/20 9:30 AM, realhet wrote:
> Hi,
> 
> struct S{
>    int[2] array;
> 
>    ref  x()       { return array[0]; }
>    auto x() const { return array[0]; }
> }
> 
> If there a way to write the function 'x' into one function, not 2 overloads.
> 
> I tried auto/const/ref mindlessly :D, also remembered 'inout', but obviously those weren't solve the problem.

Your original code is an odd situation -- you want to return by ref if it's mutable, but not if it's const?

Why not return by ref always, and just forward the constancy? This is what inout is made to do:

ref inout(int) x() inout { return array[0]; }

> 
> (This is going to be a swizzling 'system' that mimics GLSL, later I will make a template that takes 'x'as a template parameter, just wondering that the support for const and non-cons can be done easier.)

If you want to differ behavior by const, but write one function, you can use a `this` template parameter. But without seeing your real use case, you might end up writing the same amount of code.

-Steve
September 20, 2020
On Sunday, 20 September 2020 at 14:54:09 UTC, Steven Schveighoffer wrote:
> On 9/20/20 9:30 AM, realhet wrote:
>ref inout(int) x() inout { return array[0]; }

This doesn't work when I type:
v.x++;

I want to make a similar type like the GLSL vectors. Where the following thing is valid:
vec4 a, b;
a.yzw = b.xzy;

On the left there is a contiguous area of the vector a. It just starts form the 1th element, not form the 0th: a[1..4].  It could be work as an lvalue.

On the right there is a non-contiguous swizzle: [b.x, b.z, b.y]. But because it is 3 element wide, it can be assigned to the lvalue "a.yzw". This value cannot be an lvalue because the order of the elements are not the same as in memory. So it must returned as a const.

Here's what I achieved so far:

private enum swizzleRegs = ["xyzw", "rgba", "stpq"]; //vector, color, and texture component letters

struct Vec(CT, int N)
if(N>=2 && N<=4){
  alias VectorType = typeof(this);
  alias ComponentType = CT;
  enum VectorTypeName = ComponentTypePrefix ~ "vec" ~ N.text;

  CT[N] array = [0].replicate(N).array; //default is 0,0,0, not NaN.  Just like in GLSL.
  alias array this;
  enum length = N;

  ...

  static foreach(regs; swizzleRegs)
    static foreach(len; 1..N+1)
      static foreach(i; 0..N-len+1)
        static if(len==1){
1)        mixin(format!"auto %s() const { return array[%s]; }"(regs[i], i));
2)        mixin(format!"ref  %s()       { return array[%s]; }"(regs[i], i));
        }else{
3)        mixin(format!"auto %s() const { return Vec!(CT, %s)(array[%s..%s]); }"(regs[i..i+len], len, i, i+len));
4)        mixin(format!"ref  %s()       { return *(cast(Vec!(CT, %s)*) (array[%s..%s])); }"(regs[i..i+len], len, i, i+len));
        }

}

So what I feel, the mixin()-s are a bit nasty :D But sufficient for the following two criteria:

1.  immutable vec3 a; a.xy.writeln; // displays a const vec2 casting a constant memory lovation to vec2  -> 3)

2.  vec3 b;  b.g++;  // accessing the 2. component(g=green, 1based) of a vec3 with a memory reference because it is mutable.

I only want lvalues from swizzle combinations that are adjacent in memory, so I can cast them. For all the rest I'm using opDispatch(string def)() with a strict constraint on the string 'def'.

For example: a.xxxx returns vec4(a.x, a.x, a.x, a.x);
a.x01z returns vec4(a.x, a.0, a.1, a.z);

The only thing I don't want  to implement from the GLSL spec is those non-contigous swizzle assignments like:
a.zyx = vec3(1,2,3) ***
but
a.xyz = vec3(1,2,3) should work.

*** maybe with a struct that refers to the original vector and the swizzle code it could be also possible. :D
September 20, 2020
On Sunday, 20 September 2020 at 15:52:49 UTC, realhet wrote:
> On Sunday, 20 September 2020 at 14:54:09 UTC, Steven Schveighoffer wrote:
>> On 9/20/20 9:30 AM, realhet wrote:

I managed to do the constant swizzles and it seems so elegant:

  auto opDispatch(string def)() const
  if(validRvalueSwizzle(def)) //making sure that only the few thousand valid swizzles can pass through here
  {
    static if(def.startsWith('_')){ //if the swizzle definition starts with a number
      return opDispatch!(def[1..$]);
    }else{
      Vec!(CT, mixin(def.length)) res;
      static foreach(i, ch; def)
        res[i] = mixin(ch);  // ch can be one of xyzw or rgba or stpq or 0 or 1.
                             // just mix it in using the already created lvalue swizzles of (integer consts 01)
      return res;
    }
  }

I also have an idea that if I use capital letters, it shoud mean negative components. This way importing a 3d vertex could be so easy in compile time: rotated = original.xZy -> this is rotated 90 degrees around the x axis. Just need to add an uppercase check.

Never dared to go that far in compile time dlang stuff, and I love it. :D Amazing language!
September 20, 2020
On 9/20/20 11:52 AM, realhet wrote:
> On Sunday, 20 September 2020 at 14:54:09 UTC, Steven Schveighoffer wrote:
>> On 9/20/20 9:30 AM, realhet wrote:
>> ref inout(int) x() inout { return array[0]; }
> 
> This doesn't work when I type:
> v.x++;

It should, as long as v is mutable.

> I want to make a similar type like the GLSL vectors. Where the following thing is valid:
> vec4 a, b;
> a.yzw = b.xzy;

This should be straight-up opDispatch I would think. You might need a helper return that reroutes the correct items.

> The only thing I don't want  to implement from the GLSL spec is those non-contigous swizzle assignments like:
> a.zyx = vec3(1,2,3) ***
> but
> a.xyz = vec3(1,2,3) should work.

What you could do, in this case, is make your return type either a helper type that uses a slice of the original, or one that contains a copy of the data in the right order, but is not assignable.

> 
> *** maybe with a struct that refers to the original vector and the swizzle code it could be also possible. :D

Yeah, I think this might work.

-Steve
September 20, 2020
On Sunday, 20 September 2020 at 16:18:19 UTC, Steven Schveighoffer wrote:
> On 9/20/20 11:52 AM, realhet wrote:
>> On Sunday, 20 September 2020 at 14:54:09 UTC, Steven Schveighoffer wrote:
>>> On 9/20/20 9:30 AM, realhet wrote:
> Yeah, I think this might work.
>
> -Steve

That would be a 3rd category out if 4 in total:
- ref for the contiguous subVectors (vec4.init.yz is a vec2)
- const for the complicated ones (vec4.init.z0 is a vec2, 2nd component is 0)
- swizzled struct of a referenced vector: (vec4 a; a.yx is a struct that links to the original 'a' by reference and know it has to swap x and y).
- everything else that can contain any vector component at any place including constants 0 and 1. I've learned this kind of swizzling in the good old CAL/AMD_IL times.

Swizzled struct is on the righr: then it should be implicitly casted when assigning it to the left to a vector. I gotta learn that too.

In GLSL this behavior is implemented deeply in the compiler. I'm so happy in D it seems also possible :D
September 20, 2020
On Sunday, 20 September 2020 at 17:08:49 UTC, realhet wrote:
> On Sunday, 20 September 2020 at 16:18:19 UTC, Steven Schveighoffer wrote:
>> On 9/20/20 11:52 AM, realhet wrote:
>>> On Sunday, 20 September 2020 at 14:54:09 UTC, Steven Schveighoffer wrote:
>>>> On 9/20/20 9:30 AM, realhet wrote:
>> Yeah, I think this might work.

https://gist.github.com/run-dlang/4b4d4de81c20a082d72eb61307db2946

Here's a little example.
In the main() there are the requirements.
Below that is the implementation. If it is ugly, please tell me how to make it prettier :D

Once I was able to make the compiler for a really long time, so I know it is rather templates than explicit mixins. All the swizzles that cover a contiguous area are mixed in though: in a 4 element vector it is: only a few elements: "x", "y", "z", "w", "xy", "yz", "zw", "xyz", "yzw", "xyzw", "r", "g", "b", "a", "rg", "gb", "ba", "rgb", "gba", "rgba", "s", "t", "p", "q", "st", "tp", "pq", "stp", "tpq", "stpq"
For everything there is opDispatch.