Thread overview
Are we on the simplest path for working with compile time entities?
Sep 25, 2020
Stefan Koch
Sep 25, 2020
Avrina
Sep 26, 2020
Stefan Koch
September 25, 2020
Hi,

If you'll remember I recently talked about an alternative way of implementing working with compile time entities such as types.

And I was pleased about it getting attention from prominent forum members and even Walter.

I gave the example of using a static map function to get the type sizes of a tuple of types.

As a result Walters does adds the ability to get sizeof without having to interface with the type entities :
The code for just that functionality to be added is this:

                            if (fd.ident == Id.tsize)
                            {
                                // Equivalent logic to `T.sizeof` in getProperty()
                                d_uns64 sz = t.size(dve.loc);
                                if (sz != SIZE_INVALID)
                                {
                                    ret = new IntegerExp(dve.loc, sz, Type.tsize_t);
                                    return;
                                }
                            }

Is that what we want for every property of typeid ?

How many properties do we need to add to typeid to make it really usable?
UDAs?
vtbls?
member names?
offsets?

Can I get the fully qualified name from this?

September 25, 2020
On Friday, 25 September 2020 at 09:37:23 UTC, Stefan Koch wrote:
> Hi,
>
> If you'll remember I recently talked about an alternative way of implementing working with compile time entities such as types.
>
> And I was pleased about it getting attention from prominent forum members and even Walter.
>
> I gave the example of using a static map function to get the type sizes of a tuple of types.
>
> As a result Walters does adds the ability to get sizeof without having to interface with the type entities :
> The code for just that functionality to be added is this:
>
>                             if (fd.ident == Id.tsize)
>                             {
>                                 // Equivalent logic to `T.sizeof` in getProperty()
>                                 d_uns64 sz = t.size(dve.loc);
>                                 if (sz != SIZE_INVALID)
>                                 {
>                                     ret = new IntegerExp(dve.loc, sz, Type.tsize_t);
>                                     return;
>                                 }
>                             }
>
> Is that what we want for every property of typeid ?
>
> How many properties do we need to add to typeid to make it really usable?
> UDAs?
> vtbls?
> member names?
> offsets?
>
> Can I get the fully qualified name from this?

I'm not particularly fond of either approach. Saying you can optimize recursive templates, if it was that simple it would have already been done. I don't see being it being optimized unless the entire compiler was gutted, but that comes with its own problems.

Type functions, I really don't like the syntax of how it is just passing a type like a regular function. It adds syntax that is the same as what is already there but does something completely different. It adds too much complexity while pretty much replacing something without it being actually removing what's already there.

For the most part what is needed is "T...", just to be able to manipulate it with an interface that aren't templates. Basically a type that can only be used at compile time but can be anything, like "T...".

It is basically a subset of what type functions would be, without adding a whole new way to call functions.

Note `alias[]` is just a placeholder.

auto static_map(alias F, T...)()
{
    alias[] result;
    result.length = T.length;

    foreach(i, t; T)
    {
        result[i] = F!t();
    }

    return result;
}

size_t sizeOf(alias t)
{
    return t.sizeof;
}

static assert(static_map!(sizeOf, int, ushort) == [4, 2]);


There are some problems though, like how to add a type to the array, currently you can't use say, "result ~= int". It looks odd, and it has to be compile time compatible. As it would be a special type, it could be ignored or lowered to "opAssign!("~", RHS)" instead to ensure it can be calculated at CT.

Then you would be able to do something like this:


  alias[] result;
  result ~= int;
  result ~= 10;

  result[0] v = result[1]; // equivalent to `int v = 10`

Right now to do something similar you would have to instantiate templates.

  alias first = AliasSeq!(int);
  alias result = AliasSeq!(first, 10);

  result[0] v = result[1];

Because you need templates to express the same thing, where you can't use one template, you have to use a new template to define it. This is what results in requiring recursive templates that expands into more and more templates. This is really all that's needed to simplify what is currently being done. We just need a way to define a template-like generic object ('T...') as a variable instead. The compiler implementation it would just be an array that's manipulated at compile time with information it already has.

The details need to be ironed out but I feel this is a more natural inclusion, it's taking what's already there and just allowing you to use it without having to define a template.


September 25, 2020
On 9/25/20 5:37 AM, Stefan Koch wrote:
> Hi,
> 
> If you'll remember I recently talked about an alternative way of implementing working with compile time entities such as types.
> 
> And I was pleased about it getting attention from prominent forum members and even Walter.
> 
> I gave the example of using a static map function to get the type sizes of a tuple of types.
> 
> As a result Walters does adds the ability to get sizeof without having to interface with the type entities :
> The code for just that functionality to be added is this:
> 
>                              if (fd.ident == Id.tsize)
>                              {
>                                  // Equivalent logic to `T.sizeof` in getProperty()
>                                  d_uns64 sz = t.size(dve.loc);
>                                  if (sz != SIZE_INVALID)
>                                  {
>                                      ret = new IntegerExp(dve.loc, sz, Type.tsize_t);
>                                      return;
>                                  }
>                              }

Reference: https://github.com/dlang/dmd/pull/11792

This is a small-cost and small-impact change. It's very rare the size gets used with any frequency during compilation. A small step that is somewhat lateral.

The prize is https://issues.dlang.org/show_bug.cgi?id=9945.

I also added what is an obviously simpler way to go about things. It's not like a type changes size and alignment during the program: https://issues.dlang.org/show_bug.cgi?id=21276

More related stuff:

https://issues.dlang.org/show_bug.cgi?id=21277
https://issues.dlang.org/show_bug.cgi?id=21278
September 26, 2020
On Friday, 25 September 2020 at 15:25:16 UTC, Andrei Alexandrescu wrote:
>
> Reference: https://github.com/dlang/dmd/pull/11792
>
> This is a small-cost and small-impact change. It's very rare the size gets used with any frequency during compilation. A small step that is somewhat lateral.
>
> The prize is https://issues.dlang.org/show_bug.cgi?id=9945.
>
> I also added what is an obviously simpler way to go about things. It's not like a type changes size and alignment during the program: https://issues.dlang.org/show_bug.cgi?id=21276
>
> More related stuff:
>
> https://issues.dlang.org/show_bug.cgi?id=21277
> https://issues.dlang.org/show_bug.cgi?id=21278

I not concerned about the size of this individual change.
I am concerned about the direction.

Where do we end up if we extrapolate the hypothetical vector of this change?
I imagine we would end up with many tiny additions trickling in.

And those only concern types.
There are other compile time properties which you would like to query and reason about.
Such as the content of modules, the names of variables.
symbol scope (__traits(parent)) etc.

Also this increases the surface area of the language rather than increasing the depth.

Having to use tinfo.tsize;
instead of being able to use T.sizeof like you would in a template.
Which increases cognitive load by requiring more memory.