Build interface from abstract class

DigitalDesigns DigitalDesigns at gmail.com
Wed May 30 00:00:57 UTC 2018


On Tuesday, 29 May 2018 at 20:53:14 UTC, DigitalDesigns wrote:
> On Tuesday, 29 May 2018 at 20:26:52 UTC, arturg wrote:
>> On Tuesday, 29 May 2018 at 19:06:24 UTC, DigitalDesigns wrote:
>>> On Monday, 28 May 2018 at 22:15:40 UTC, arturg wrote:
>>>> this might help you,
>>>> https://dpaste.dzfl.pl/2cf844a11e3f
>>>>
>>>> you can use them to generate the functions as strings.
>>>
>>> Thanks,
>>>
>>> So, the problem I'm having is that I cannot use the generated 
>>> interface for the abstract class because the abstract class 
>>> needs the interface defined. I need to be able to forward 
>>> define the interface then extend it.
>>>
>>> D doesn't like this
>>>
>>> main.d(10): Error: interface `main.B` base `A` is forward 
>>> referenced
>>>
>>> interface A;
>>> mixin(Generate!(B,A));
>>> interface B : A
>>> {
>>>
>>> }
>>>
>>> abstract class C : B
>>> {
>>>
>>> }
>>>
>>
>> would it work if you define the interface but mixin the 
>> members?
>>
>> interface A
>> {
>>     mixin(InterfaceFromClass!C);
>> }
>
> Yes, I made a post about it but it didn't get through or I 
> forgot to send ;/
>
> Doing it this way solves the original problems but creates a 
> new problem in that any class that inherits from an abstract 
> class that implements A doesn't work.
>
> interface A
> {
>     mixin(InterfaceFromClass!C);
> }
>
> abstract class B : A
> {
>     A foo() { return this; }
>     int bar() { return 3; }
> }
>
>
> class C : B
> {
>     // compiler says foo, bar not implemented
> }
>
>
> so, instead
>
> interface A
> {
>     mixin(InterfaceFromClass!C);
> }
>
> abstract class B
> {
>     A foo() { return this; } // requires cast
>     int bar() { return 3; }
> }
>
>
> class C : B, A
> {
>
> }
>
>
> works but requires casting this in B which happens to work in 
> C. So It is a fessible solution but I'm not sure why the 
> compiler things the first case doesn't implement the methods 
> when it clearly does. I think it looks at A and doesn't compute 
> the mixin first when parsing C because if I put the output of 
> the mixin directly it works. Probably a bug...



This method, which imports the source code and extracts the 
members works but is very fragile and requires using -J:



// Directly copies the data to the interface with a few hacks to 
fix the bug from the original, it excepts a well formatted input


template InterfaceFromClass(alias T)
{

	string InterfaceFromClass(string file = __FILE_FULL_PATH__)()
	{
		string res;
		import std.path, std.string, std.algorithm;
		enum data = import(file.baseName);
		enum mc = "abstract class "~T.stringof~" : ";
		enum im = `@("InterfaceMembers")`;
		int level = 0;
		auto baseIndentLevel = -1;
		int funcIndentLevel = -1;
		foreach(v; data.splitLines)
		{
			string l = v;
			auto indentLevel = l.length - l.stripLeft().length;
			auto ll = l.strip();
			if (ll.length == 0) continue;
			
			//res ~= to!string(l.length) ~"\n" ~ l[0..min(mc.length, 
l.length)] ~ "\n";
			if (level == 0 && ll.length >= mc.length && 
ll[0..min(mc.length, ll.length)] == mc) { baseIndentLevel = 
indentLevel; level = 1; continue; }	// Finds "abstract class <T> 
: "
			if (level == 1 && ll.length >= im.length && 
ll[0..min(im.length, ll.length)] == im) { level = 2; continue; 
}	// Finds "@("InterfaceMembers))" near by
			if (level >= 2 && l == "}") break;
			if (level == 2 && ll.length > 1)
			{
				if (funcIndentLevel < 0) funcIndentLevel = indentLevel;
				if (funcIndentLevel < indentLevel) continue;

				// A simple function definition(ends with a ');')
				if (!ll.canFind("=") && l.length > 2 && l[$-2..$] == ");") { 
res ~= l ~ "\n"; continue; }
				// ignore fields(assumes it has no {, } but ends with a ';')
				if (!ll.canFind("{") && l[$-1] == ';' && ll[$-2..$] != "};") 
continue;

				// ignore functions with inline blocks
				if (ll.canFind(") {")) { l = l[0..$ - ll.find(") {").length] 
~ ")"; }
				
				// must get function signature only(ignore body)				
				res ~= l ~ ((ll[$] != ';') ? ";" : "") ~ "\n";

			}
		}
		

		return res;
	}
}


Why the original code is being broke by using D's traits to build 
the functions properly is beyond me. I'm pretty sure it is a bug 
given the example I gave earlier.




More information about the Digitalmars-d-learn mailing list