www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - Symbol Registration

reply Richard (Rikki) Andrew Cattermole <richard cattermole.co.nz> writes:
For a long time now (~10 years), I've wanted a cheap way of 
registering symbols for frameworks to operate on. Existing 
registration schemes are expensive, and slow. They usually 
require some effort on the programmer to make happen, not ideal.

A solution to this can be seen in ``ModuleInfo`` and 
``xgetmembers``, have the compiler perform the registration of a 
symbol transformed into a descriptor list that then can be used 
to do stuff with at runtime.

However existing methods are not geared up to be used by a 
library writer for registration of custom data, this proposal 
offers a way to do this registration cleanly and effortlessly by 
the user. So they can focus on their goal rather than the how.

In this design, UDA's trigger registration of a symbol, but this 
UDA must first have an attribute specific to the list placed upon 
it.

In core.attributes the following mixin template implements the 
list mechanism.

```d
mixin template ListOfSymbolState(SymbolState, alias 
SymbolTransformation) {
     private MySymbolState/* ... */ symbolStates;

     enum Attribute;

     ptrdiff_t length();
     int opApply(scope int delegate(immutable ref SymbolState) 
 safe nothrow  nogc)  safe nothrow  nogc;
}
```

To use it as a library writer:

```d
module library.registration;

 mySymbolStates.Attribute
struct Route {
     string path;
}

mixin ListOfSymbolState!(MySymbolState, MySymbolTransformation) 
mySymbolStates;

package(library):

struct MySymbolState {
     string fqn, name;
}

template MySymbolTransformation(alias symbol) {
     enum MySymbolTransformation = 
MySymbolstate(__traits(fullyQualifiedName, symbol), 
__traits(identifier, symbol));
}
```

By the user:

```d
import library.registration;

 Route("/")
void myRoute() {

}
```

When the enum ``Attribute`` in ``ListOfSymbolState`` is placed 
upon a symbol, that symbol when used as a UDA will trigger 
registration.

Registration is done on a symbol, that is then transformed using 
``SymbolTransformation`` a template, that results in a value of 
``SymbolState`` which must be a struct.

A ``SymbolState`` is stored in a list ``symbolStates`` that 
external code does not have direct access to.

The list is compiler and linker defined sequence of elements. 
Common strategies for this are linked lists and section 
appending. Due to the possibility of moving by the loader, no 
interior pointers are allowed in ``SymbolState`` or to an element.

Exportation of the list is compiler and platform defined, assume 
that it is not exported, and each binary must be registered 
separately. See dub's ``injectSourceFiles`` directive for how to 
do this.

This will enable deserialization, orm's, web routes, game logic, 
GUI controls, to self register.
Sep 25 2024
next sibling parent ryuukk_ <ryuukk.dev gmail.com> writes:
I did something like that once, i agree it should be greatly 
simplified


```D
     alias THIS_MODULE = game.states.gameplay;
     static foreach (member; __traits(allMembers, THIS_MODULE))
     {
         static foreach (attr; __traits(getAttributes, 
__traits(getMember, THIS_MODULE, member)))
         {
             static if (is(typeof(attr) == PacketType))
             {
                 if(type == attr)
                 {
                     found = true;
                     handled = true;

                     // check if it has params
                     static if (is(typeof( __traits(getMember, 
THIS_MODULE, member)) params == __parameters))
                     {
                         // LINFO("Packet Handler found: {} {}", 
attr, member.ptr);
                         // LINFO("Param: {}", 
params[0].stringof.ptr);

                         // get type of the packet (from the 
function parameter)
                         alias ptype = typeof(*params[0]);
                         static if (__traits(hasMember, ptype, 
"write") == false) static assert(0);

                         auto data = ptype();

                         static if (__traits(hasMember, ptype, 
"allocator"))
                         {
                             data.allocator = 
state.ctx.engine.arena.allocator();
                         }

                         data.read(&reader);
                         __traits(getMember, THIS_MODULE, 
member)(&data);
                     }
                 }
             }
         }
     }
```


```D
 (PacketType.RECONNECT)
void handle_reconnect(ReconnectPacket* rec)
{
     disconnect();
     state.net_info.host = rec.host;
     state.net_info.port = rec.port;
     state.net_info.connect_timer = 1.0;
}
``

I can never remember how to do it, never
Sep 25 2024
prev sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Wednesday, 25 September 2024 at 17:09:04 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 For a long time now (~10 years), I've wanted a cheap way of 
 registering symbols for frameworks to operate on. Existing 
 registration schemes are expensive, and slow. They usually 
 require some effort on the programmer to make happen, not ideal.
I am supportive of your proposal, particularly as the following points align perfectly with the D language philosophy: 1. Automating the registration process with a simple UDA, such as ``` Route```, will allow developers to focus solely on the business logic. 2. Moving the registration process from runtime to the compile and link phases will significantly enhance the loading speed of our frameworks. However, I think we should be cautious about a couple of points: * This requires a major change at the compiler and linker level. This is a substantial architectural shift, and it may take time for existing toolchains (e.g., dmd, ldc, gdc, and other third-party tools) to fully support this new mechanism. What do you think? * The constraint that ```SymbolState``` structs are not allowed to contain interior pointers could force a retreat to existing, flexible runtime solutions in some complex scenarios. We must carefully balance the trade-off between the benefits of this constraint (security, simplicity) and the loss of flexibility. Best regards, SDB 79
Nov 22 2025