On Sunday, 3 June 2018 at 09:52:01 UTC, Malte wrote:
On Saturday, 2 June 2018 at 23:12:46 UTC, DigitalDesigns wrote:
On Thursday, 7 September 2017 at 22:53:31 UTC, Biotronic wrote:
[...]

I use something similar where I use structs behaving like enums. Each field in the struct is an "enum value" which an attribute, this is because I have not had luck with using attributes on enum values directly and that structs allow enums with a bit more power.

[...]

You might want to have a look at https://wiki.dlang.org/Dynamic_typing This sounds very similar to what you are doing. I never really looked into it, because I prefer to know which type is used and give me errors if I try to do stupid things, but I think it's a cool idea.

No, this is not what I'm talking about, although maybe it could be related in some way.

What I am talking about is hooking up a runtime variable that can take a few values, such as from an enum and have those be mapped to a compile time template value.

This way you get full static time checking of runtime code. Seems impossible? It's not!

What it does is leverage D's meta programming engine to deal with all the routine possiblities.

A large switch statement is what makes the runtime to compile time magic happen

int x;

switch(x)
{
    default: foo!void();
    case 0: foo!int();
    case 1: foo!double();
    etc...
}

See how the switch maps a runtime value x to a templated function foo?

we then can handle the x values with foo

void foo(T)()
{
   // if x = 0 then T = int
   // if x = 1 then T = double


}

But inside foo we have T, the template variable that is the compile time representation of the dynamic variable x. Remember, x's value is unknown at compile time... the switch is what maps the runtime to the compile time.

But in foo, because we have T, the type system all works fine.

What makes this very useful that we can call templated functions using T and the meta engine will pick the right template function specialization.

e.g.,

void bar(S)()
{

}


can be used inside foo by calling bar!T(). It doesn't seem like much here if you had to use x it would be a pain. Either you would have to manually create switches or create a rats nest of if statements. But we never have to worry about that stuff when using the above method because it is exactly like programming at compile time as if x a compile time value(like say, just int).

It works great when you have several template variables and just want everything to work together without having to go in to much trouble:


foo(A,B)()
{
   B b = 4;
   bar!(A)(b)
}


suppose A can come from int, double, and B from float and long

That is 4 different combinations one would normally have to represent. Not a big deal until you have to handle every combination.


Suppose you are working with void arrays. They contain types but you don't know the type except after compile time.

Without using this technique you have to use casts and tricks and you'll find out if you screwed up some typing stuff at runtime. Using this technique you will not have a void array but a T[] with T being any of the possible types that you specify using UDA's.

if you could

if (x == 0)
{
    foo(cast(int[])a);
} else

if (x == 1)
{
    foo(cast(double[])a);
} else


but I can do that with one line which simply generates the switch for me. Really all I'm doing is hiding the switch so it all looks like some magic is happening in one line. But the fact that it becomes really simple to do seems to open up the use of it and conceptually on can then think of "x" as a compile time variable that can take on several possibilities.



Reply via email to