Thread overview
Static indexing
Jan 12, 2022
JG
Jan 12, 2022
Ali Cehreli
Jan 12, 2022
H. S. Teoh
January 12, 2022

Hi,

I want to make a type which has two fields x and y but can
also be indexed with [0] and [1] checked at compile time.

Is the following reasonable / correct?

struct Point
{
  double x;
  double y;
  alias expand = typeof(this).tupleof;
  alias expand this;
}
unittest
{
  Point p = Point(1.2,3.4);
  assert(p[0]==1.2);
  assert(p[1]==3.4);
  assert(!__traits(compiles,Point.init[3]));
}
January 12, 2022
On 1/12/22 00:59, JG wrote:

> I want to make a type which has two fields x and y but can
> also be indexed with [0] and [1] checked at compile time.

std.typecons.Tuple already does that. You can add "member functions" like foo() below by taking advantage of UFCS:

import std.typecons;

alias Point = Tuple!(double, "x", double, "y");

unittest
{
  Point p = Point(1.25,3.5);
  assert(p[0]==1.25);
  assert(p.x==1.25);
  assert(p[1]==3.5);
  assert(p.y==3.5);
  assert(!__traits(compiles,Point.init[3]));
}

void foo(ref Point p) {
  p.x += p.y;
}

unittest {
  auto p = Point(1.5, 2.75);
  p.foo();
  assert(p.x == 4.25);
  assert(p.y == 2.75);
}

void main() {
}

Also note, I changed all the floating point values to ones that can be fully representable by floating point types so that the unit tests would always succeed. (For example, 0.1 and 0.4 etc. cannot be represented fully but 0.5 and 0.25 etc. can be.)

Ali

January 12, 2022

On 1/12/22 3:59 AM, JG wrote:

>

Hi,

I want to make a type which has two fields x and y but can
also be indexed with [0] and [1] checked at compile time.

Is the following reasonable / correct?

    struct Point
    {
      double x;
      double y;
      alias expand = typeof(this).tupleof;
      alias expand this;
    }
    unittest
    {
      Point p = Point(1.2,3.4);
      assert(p[0]==1.2);
      assert(p[1]==3.4);
      assert(!__traits(compiles,Point.init[3]));
    }

I was going to reply that you can't do it this way, but it works. Very interesting!

I would say to go with that, and I love that technique! Seems like it started allowing alias to tupleof in 2.094.

std.typecons.Tuple does it much differently. It declares the tuple as an alias-this'd member, and then defines named accessors for each of the items (if you give them names).

One thing I did find is that foreach doesn't like your mechanism, whereas the Tuple mechanism does work:

foreach(x, y; only(Point(1.0, 2.0)) {} // error
foreach(x, y; only(tuple(1.0, 2.0)) {} // ok

-Steve

January 12, 2022
On Wed, Jan 12, 2022 at 11:04:59AM -0500, Steven Schveighoffer via Digitalmars-d-learn wrote:
> On 1/12/22 3:59 AM, JG wrote:
[...]
> >      struct Point
> >      {
> >        double x;
> >        double y;
> >        alias expand = typeof(this).tupleof;
> >        alias expand this;
> >      }
[...]
> I was going to reply that you can't do it this way, but it works. Very interesting!
> 
> I would say to go with that, and I love that technique! Seems like it started allowing alias to `tupleof` in 2.094.
[...]

Yeah, I was also going to say, this is a very interesting trick indeed! I might actually adopt this for one of my projects, instead of the more complex CTFE-generated mixin I'm currently using.


T

-- 
Making non-nullable pointers is just plugging one hole in a cheese grater. -- Walter Bright