August 31, 2017
On Wednesday, 30 August 2017 at 22:52:41 UTC, Adam D. Ruppe wrote:
> On Wednesday, 30 August 2017 at 20:47:12 UTC, EntangledQuanta wrote:
>> This is quite surprising!
>
> In the new version pending release (scheduled for later this week), we get a new feature `static foreach` that will let you loop through the types you want and declare all the functions that way.
>
> When it is released, we'll have to take a second look at this problem.

I've already implemented a half ass library solution. It works, but is not robust. The compiler can and should do this!




string OverLoadTemplateDefinition(string name, alias func, T...)()
{
	import std.string;
	string str;
	foreach(t; T) str ~= ((func!t).stringof).replace("function(", name~"(")~";\n";
	return str;
}

string OverLoadTemplateMethod(string name, alias func, T...)()
{
	import std.traits, std.algorithm, std.meta, std.string;

	alias RT(S) = ReturnType!(func!S);
	alias PN(S) = ParameterIdentifierTuple!(func!S);
	alias P(S) = Parameters!(func!S);
	alias PD(S) = ParameterDefaults!(func!S);

	string str;
	foreach(t; T)
	{
		str ~= (RT!t).stringof~" "~name~"(";
		foreach(k,p; P!t)
		{
			auto d = "";
			static if (PD!t[k].stringof != "void")
				d = " = "~(PD!t)[k].stringof;
			str ~= p.stringof~" "~(PN!t)[k]~d;
			if (k < (P!t).length - 1)
				str ~= ", ";
		}
		
		str ~= ") { _"~name~"(";
		foreach(k, n; PN!t)
		{
			str ~= n;
			if (k < (P!t).length - 1)
				str ~= ", ";
		}
		str ~= "); }\n";
	}
	return str;
}


They are basically the generic version of what Jonathan implemented by hand.

In the interface:

private alias _Go(T) = void function();

mixin(OverLoadTemplateDefinition!("Go", _Go, int, short, float, double)());

In class:

mixin(OverLoadTemplateMethod!("Go", _Go, int, short, float, double)());

protected final void _Go(T)()
	{
....
	}


The alias simply defines the function that we are creating. The mixin OverLoadTemplateDefinition creates the N templates.

in the class, we have to do something similar but dispatch them to the protected _Go... very similar to what Jonathan did by hand. But the code to do so is not robust and will break in many cases because I left a lot of details out(linkage, attributes, etc).

It is a proof of concept, and as you can see, it is not difficult. The compiler, and anyone that has a decent understanding of the internals of it, should be able to implement something quite easily.

Maybe it is also possible to use OpCall to do something similar?

I'd like to reiterate that this is not an insolvable problem or an NP problem. It is quite easy. If we require restricting the types to a computable set, it is just simple overloading and templatizing to reduce the complexity.

Having the compiler to this can reduce the noise and increase the robustness and also provide a nice feature that it currently does not have, but should.

Using templates with inheritance is a good thing, It should be allowed instead of blinding preventing all cases when only one case is uncomputable. The logic that some are using is akin to "We can't divide by 0 so lets not divide at all", but of course, division is very useful and one pathological case doesn't prevent all other cases from being useful.

August 30, 2017
On 08/30/2017 05:49 PM, EntangledQuanta wrote:

> The compiler can and should do this!

Yes, the compiler can do it for each compilation but there is also the feature called /separate compilation/ that D supports. With separate compilation, there would potentially be multiple different and incompatible definitions of the same interface because compilations cannot know the whole set of instantiations of templates.

This relatively popular request is impossible in D as well as other languages like C++ that practically settled on vtbl-based polymorphism.

Ali

August 31, 2017
On Thursday, 31 August 2017 at 00:49:22 UTC, EntangledQuanta wrote:
> I've already implemented a half ass library solution.

It can be improved alot.
August 31, 2017
On Thursday, 31 August 2017 at 10:34:14 UTC, Kagamin wrote:
> On Thursday, 31 August 2017 at 00:49:22 UTC, EntangledQuanta wrote:
>> I've already implemented a half ass library solution.
>
> It can be improved alot.

Then, by all means, genius!
September 01, 2017
On Thursday, 31 August 2017 at 15:48:12 UTC, EntangledQuanta wrote:
> On Thursday, 31 August 2017 at 10:34:14 UTC, Kagamin wrote:
>> On Thursday, 31 August 2017 at 00:49:22 UTC, EntangledQuanta wrote:
>>> I've already implemented a half ass library solution.
>>
>> It can be improved alot.
>
> Then, by all means, genius!

Enjoy!

mixin template virtualTemplates(alias parent, alias fn, T...) {
    import std.meta;
    alias name = Alias!(__traits(identifier, fn)[1..$]);
    mixin virtualTemplates!(parent, name, fn, T);
}

mixin template virtualTemplates(alias parent, string name, alias fn, T...) {
    import std.traits;
    static if (is(parent == interface)) {
        template templateOverloads(string name : name) {
            alias templateOverloads = T;
        }
        alias Types = T;
    } else {
        alias Types = templateOverloads!name;
    }

    mixin(virtualTemplatesImpl(name, Types.length, is(parent == class)));
}

string virtualTemplatesImpl(string name, int n, bool implement) {
    import std.format;
    string result;
    foreach (i; 0..n) {
        auto body = implement ? format(" { return fn!(Types[%s])(args); }", i) : ";";
        result ~= format("ReturnType!(fn!(Types[%s])) %s(Parameters!(fn!(Types[%s])) args)%s\n", i, name, i, body);
    }
    return result;
}

interface I {
    void _Go(T)(T s);
    void _Leave(T)(T s);
    mixin virtualTemplates!(I, _Go, int, short, float, double);
    mixin virtualTemplates!(I, "Abscond", _Leave, int, short, float, double);
}

class C : I {
    void _Go(T)(T s) { }
    void _Leave(T)(T s) { }
    mixin virtualTemplates!(C, _Go);
    mixin virtualTemplates!(C, "Abscond", _Leave);
}

unittest {
    I c = new C();

    c.Go(3.2);
    c.Abscond(3.4f);
}

Does not support multiple template parameters, or template value parameters. Use at own risk for any and all purposes.
September 01, 2017
static foreach is now in the new release! You can now do stuff like:

---
alias I(A...) = A;

interface Foo {
        static foreach(T; I!(int, float))
                void set(T t); // define virt funcs for a list of types
}

class Ass : Foo {
        static foreach(T; I!(int, float))
                void set(T t) {
                        // simplement
                }
}
---


really easily.
September 01, 2017
On Friday, 1 September 2017 at 15:24:39 UTC, Adam D. Ruppe wrote:
> static foreach is now in the new release! You can now do stuff like:
>
> ---
> alias I(A...) = A;
>
> interface Foo {
>         static foreach(T; I!(int, float))
>                 void set(T t); // define virt funcs for a list of types
> }
>
> class Ass : Foo {
>         static foreach(T; I!(int, float))
>                 void set(T t) {
>                         // simplement
>                 }
> }
> ---
>
>
> really easily.

I get an access violation, changed the code to

	import std.meta;
	static foreach(T; AliasSeq!("int", "float"))
		mixin("void set("~T~" t);");


and also get an access violation ;/

September 01, 2017
On Friday, 1 September 2017 at 18:17:22 UTC, EntangledQuanta wrote:
> I get an access violation, changed the code to

What is the rest of your code? access violation usually means you didn't new the class...
September 01, 2017
On Friday, 1 September 2017 at 19:25:53 UTC, Adam D Ruppe wrote:
> On Friday, 1 September 2017 at 18:17:22 UTC, EntangledQuanta wrote:
>> I get an access violation, changed the code to
>
> What is the rest of your code? access violation usually means you didn't new the class...

No, that is the code! I added nothing. Try it out and you'll see. I just upgraded to released dmd too.


alias I(A...) = A;

interface Foo {
        static foreach(T; I!(int, float))
                void set(T t); // define virt funcs for a list of types
}

class Ass : Foo {
        static foreach(T; I!(int, float))
                void set(T t) {
                        // simplement
                }
}

void main()
{

}

try it.


September 01, 2017
This happens when building, not running. This might be a Visual D issue as when I use dmd from the command line, it works fine ;/