New programming paradigm

EntangledQuanta via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Sun Sep 3 20:26:23 PDT 2017


In coming up with a solution that maps enums to templates, I 
think it might provide a means to allow template like behavior at 
runtime. That is, type information is contained with in the enum 
which then can, with the use of compile time templates, be 
treated as dynamic behaviors.

Let me explain:

Take a variant type. It contains the "type" and the data. To 
simplify, we will treat look at it like

(pseudo-code, use your brain)

enum Type { int, float }

foo(void* Data, Type type);

The normal way to deal with this is a switch:

switch(type)
{
     case int: auto val = *(cast(int*)Data);
     case float: auto val = *(cast(float*)Data);
}


But what if the switch could be generated for us?

Instead of

foo(void* Data, Type type)
{
   switch(type)
   {
       case int: auto val = *(cast(int*)Data);
       case float: auto val = *(cast(float*)Data);
   }
}

we have

foo(T)(T* Data)
{

}


which, if we need to specialize on a type, we can do

foo(int* Data) { }
foo(float* Data) { }


One may claim that this isn't very useful because it's not much 
different than the switch because we might still have to do 
things like:

foo(T)(T* Data)
{
   static switch(T)
    {
      case int: break;
      case float: break;
    }
}

but note that it is a CT switch.

But, in fact, since we can specialize on the type we don't have 
to use switch and in some cases do not even need to specialize:

for example:

foo(T)(T* Data) { writeln(*Data); }

is a compile time template that is called with the correct type 
value at run-time due to the "magic" which I have yet to 
introduce.

Note that if we just use a standard runtime variant, writeln 
would see a variant, not the correct type that Data really is. 
This is the key difference and what makes this "technique" 
valuable. We can treat our dynamic variables as compile time 
types(use the compile time system) without much hassle. They fit 
naturally in it and we do not clutter our code switches. We can 
have a true auto/var like C# without the overhead of the IR. The 
cost, of course, is that switches are still used, they are 
generated behind the scenes though and the runtime cost is a few 
instructions that all switches have and that we cannot avoid.


To get a feel for what this new way of dealing with dynamic types 
might look like:

void foo(var y) { writeln(y); }

var x = "3"; // or possibly var!(string, int) for the explicit 
types used
foo(x);
x = 3;
foo(x);

(just pseudo code, don't take the syntax literally, that is not 
what is important)

While this example is trivial, the thing to note is that there is 
one foo declared, but two created at runtime. One for string and 
one for and int. It is like a variant, yet we don't have to do 
any testing. It is very similar to `dynamic` in C#, but better 
since actually can "know" the type at compile time, so to speak. 
It's not that we actually know, but that we write code as if we 
knew.. it's treated as if it's statically typed.

In fact, we still have to specify the possible types a value can 
take on(just like variant), but once that is done the switch 
statement can be generated and we just have to write our 
templated function to handle this new "type".

You can see some of the code here, which I won't repeat for sake 
of brevity:

https://forum.dlang.org/thread/qtnawzubqocllhacuokq@forum.dlang.org

The thing to note, is that by defining foo in a specific way, the 
mixin generates a proxy that creates the switch statement for us. 
This deals with casting the type by using the type specifier and 
calling the template with it.

If the compiler were to use such a type as a first class citizen, 
we would have a very easy and natural way for dealing with 
dynamic types that can only have a finite number of type 
specializations. This should be the general case, although  I 
haven't looked at how it would work with oop. The cost is the 
same as any dynamic type... a switch statement, which is just a 
few extra cycles. (a lookup table could be used, of course, but 
not sure the benefit)


As far as I know, no other language actually does this. Those 
with dynamic types have a lot more overhead since they don't 
couple them with templates(since they are not a statically typed 
language).

Anyways, not a thoroughly thought out idea, but actually if it 
works well(I'm using the code I linked to and it works quite well 
for dealing with buffers that can take several different times. 
One function, no explicit switching in it) and could be 
implemented in the compiler, would probably be a very nice 
feature for D?

One of the downsides is code bloat. Having multiple var's 
increase the size O(n^m) since one has to deal with every 
combination. These result in very large nested switch 
structures... only O(m) to transverse at runtime though, but 
still takes up a lot of bits to represent.






More information about the Digitalmars-d-learn mailing list