Thread overview
Do you want to help me fix static AA initialization?
Jul 03, 2023
Stefan Koch
Jul 25
RazvanN
Jul 27
RazvanN
June 29, 2023

Hi everyone,

I have a fix for static associative array initialization. Basically, I have a project called newaa which is a library-based copy of D's associative arrays. The url is here: https://github.com/schveiguy/newaa

This allows static initialization of AAs, e.g.:


Hash!(string, string) ctaa = [
   "name" : "Steve",
   "username" : "schveiguy"
];

void main()
{
   string[string] aa = ctaa.asAA;
}

If you look at the project, you can see that asAA actually is just a reinterpret cast of the internals, since the layout is exactly the same. The actual AA is built at compile time, and just used at runtime, without any issues (and yes, the mutability is fine).

I want to make this part of the language/library, such that you can just straight-up initialize AA's at compile time and use them at runtime.

However, I need the compiler's help. Why? Because CTFE does not let you retinterpret cast, plus it doesn't have a distinct type for "runtime AA" vs. "compile time AA" (these are distinct types). So I need some kind of hook to cross the barrier, where the compiler ignores the return type not being an AA and just bludgeons it into an AA location. I also need it to call this hook only when going to convert the AA from CT to RT, including if it is a member in some CT structure.

Does anyone have the skills to help me? Hit me here, or on discord, or send me an email: schveiguy@gmail.com

BTW, this fix in principle is tentatively approved by Walter for inclusion (assuming everything we thought of is kosher with the language). As long as it doesn't break any existing code, and just allows currently non-working code to just work.

-Steve

July 03, 2023

On Thursday, 29 June 2023 at 19:48:40 UTC, Steven Schveighoffer wrote:

>

Hi everyone,

I have a fix for static associative array initialization. Basically, I have a project called newaa which is a library-based copy of D's associative arrays. The url is here: https://github.com/schveiguy/newaa

[...]

I have copied the druntime implementation of AAs into the dmd compiler and allowed it to build static array literals.
It needs some work to make it really generic but it would be something to look at:
https://github.com/dlang/dmd/compare/master...UplinkCoder:dmd:aaConstantLiteral

July 03, 2023

On 7/3/23 10:18 AM, Stefan Koch wrote:

>

On Thursday, 29 June 2023 at 19:48:40 UTC, Steven Schveighoffer wrote:

>

Hi everyone,

I have a fix for static associative array initialization. Basically, I have a project called newaa which is a library-based copy of D's associative arrays. The url is here: https://github.com/schveiguy/newaa

[...]

I have copied the druntime implementation of AAs into the dmd compiler and allowed it to build static array literals.
It needs some work to make it really generic but it would be something to look at:
https://github.com/dlang/dmd/compare/master...UplinkCoder:dmd:aaConstantLiteral

Thanks for the link, but I think this is the wrong approach. The compiler shouldn't have a separate identical implementation internally, that means we have to maintain 2 identical implementations, and more unspoken dependencies from compiler to library (someone could make a minor change in the library version and forget to update the compiler, resulting in odd behaviors or crashes). What we need is a library implementation that can do this work during CTFE.

However, I appreciate the link, because maybe I can actually figure out where to properly add the right calls.

-Steve

July 21

On Thursday, 29 June 2023 at 19:48:40 UTC, Steven Schveighoffer wrote:

>

I have a fix for static associative array initialization.

Cool!

>

This allows static initialization of AAs, e.g.:


Hash!(string, string) ctaa = [
   "name" : "Steve",
   "username" : "schveiguy"
];

void main()
{
   string[string] aa = ctaa.asAA;
}

Dumb user question: Presuming this is fixed would it allow code that looked like this:

import std.stdio: writeln;

auto aa = ["one":1, "two":2];

void main(){
    writeln(aa["one"]);
}

to work, or would the end result require Hash!(string, string) as the type definition?

July 21

On Friday, 21 July 2023 at 06:24:09 UTC, Chris Piker wrote:

>

Dumb user question: Presuming this is fixed would it allow code that looked like this: auto aa = ["one":1, "two":2];
to work, or would the end result require Hash!(string, string) as the type definition?

As far as I understand, it would be the former. It’s only not in Steven’s examples because his Hash template is not in the runtime and of course not special-cased by the compiler. He asks for help to get exactly there.

July 22

On 7/21/23 4:55 AM, Quirin Schroll wrote:

>

On Friday, 21 July 2023 at 06:24:09 UTC, Chris Piker wrote:

>

Dumb user question:  Presuming this is fixed would it allow code that looked like this: auto aa = ["one":1, "two":2];
to work, or would the end result require Hash!(string, string) as the type definition?

As far as I understand, it would be the former. It’s only not in Steven’s examples because his Hash template is not in the runtime and of course not special-cased by the compiler. He asks for help to get exactly there.

Yes, you are correct.

The goal is not to have a Hash type, but to have a mechanism for the compiler to convert a CTFE AA to a runtime AA. The Hash type is just a demonstration that it can be done.

BTW, fun stuff, I've learned that the CTFE AA is actually implemented using 2 CTFE arrays. So maybe... it might be also better to just replace it with a CTFE-compatible library type. But there are other tricks that need to be figured out (AAs have some magic properties).

-Steve

July 25

On Thursday, 29 June 2023 at 19:48:40 UTC, Steven Schveighoffer wrote:

>

Hi everyone,

I have a fix for static associative array initialization. Basically, I have a project called newaa which is a library-based copy of D's associative arrays. The url is here: https://github.com/schveiguy/newaa

This allows static initialization of AAs, e.g.:


Hash!(string, string) ctaa = [
   "name" : "Steve",
   "username" : "schveiguy"
];

void main()
{
   string[string] aa = ctaa.asAA;
}

If you look at the project, you can see that asAA actually is just a reinterpret cast of the internals, since the layout is exactly the same. The actual AA is built at compile time, and just used at runtime, without any issues (and yes, the mutability is fine).

I want to make this part of the language/library, such that you can just straight-up initialize AA's at compile time and use them at runtime.

However, I need the compiler's help. Why? Because CTFE does not let you retinterpret cast, plus it doesn't have a distinct type for "runtime AA" vs. "compile time AA" (these are distinct types). So I need some kind of hook to cross the barrier, where the compiler ignores the return type not being an AA and just bludgeons it into an AA location. I also need it to call this hook only when going to convert the AA from CT to RT, including if it is a member in some CT structure.

Does anyone have the skills to help me? Hit me here, or on discord, or send me an email: schveiguy@gmail.com

BTW, this fix in principle is tentatively approved by Walter for inclusion (assuming everything we thought of is kosher with the language). As long as it doesn't break any existing code, and just allows currently non-working code to just work.

-Steve

Maybe this has been addressed in previous discussions, but why not rewrite:

int[string] b = ["mimi" : 2];

to

int[string] b;

    static this()
    {
        b = ["mimi" : 2];
    }
    ```

I know that we have problems with cycle detection in module constructors, but assuming this will be fixed by Adam's proposal, this seems like a lot easier to implement and does not stress compilation time.

RazvanN
July 25

On 7/25/23 4:45 AM, RazvanN wrote:

>

Maybe this has been addressed in previous discussions, but why not rewrite:

int[string] b = ["mimi" : 2];

to

int[string] b;

     static this()
     {
         b = ["mimi" : 2];
     }
     ```

I know that we have problems with cycle detection in module constructors, but assuming this will be fixed by Adam's proposal, this seems like a lot easier to implement and does not stress compilation time.

Yes, this can be done. We can even mark the static ctor as standalone, so it doesn't participate in cycles.

And then in the future if we can find a way to do it during CTFE, then it can be seamlessly changed.

There are some hairy aspects -- like what you do if the initialized value is done in a function call or the AA is a member of a type instead of the thing being initialized, but those are surmountable.

Great idea!

-Steve

July 27

On Tuesday, 25 July 2023 at 13:24:32 UTC, Steven Schveighoffer wrote:

>

On 7/25/23 4:45 AM, RazvanN wrote:

>

Maybe this has been addressed in previous discussions, but why not rewrite:

int[string] b = ["mimi" : 2];

to

int[string] b;

     static this()
     {
         b = ["mimi" : 2];
     }
     ```

I know that we have problems with cycle detection in module constructors, but assuming this will be fixed by Adam's proposal, this seems like a lot easier to implement and does not stress compilation time.

Yes, this can be done. We can even mark the static ctor as standalone, so it doesn't participate in cycles.

And then in the future if we can find a way to do it during CTFE, then it can be seamlessly changed.

There are some hairy aspects -- like what you do if the initialized value is done in a function call or the AA is a member of a type instead of the thing being initialized, but those are surmountable.

Great idea!

-Steve

There are some issues with this proposal though:

  • accepting the static initializer leaves the impression that the initializer code is CTFEable when actually it could be not.
  • immutable AAs should be usable at compile time, whereas with this proposal they would not be because they are initialized at runtime (we could just say you can slap enum instead of immutable to make it work, but that's not how language design should be fone.)
  • there is no way that I know where static variables inside function scopes can be accessed from the outside.

Overall, this starts to look like a hack.