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/qtnawzubqocllhacu...@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.




Reply via email to