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