Re: Build interface from abstract class

2018-05-30 Thread DigitalDesigns via Digitalmars-d-learn

On Wednesday, 30 May 2018 at 10:31:27 UTC, Simen Kjærås wrote:

On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote:
I do not think this is a problem in D. Infinite recursion can 
always be terminated with appropriate means.


1. Use attributes. methods in class A should be marked as 
being for the interface. When added to the interface they will 
not have the attribute so will not be picked up again.


2. Your method of function creation does not pick up 
attributes and other factors so it is weak.


Here is my solution that does not solve problem 2:

[Neat stuff]


Neat, but as you say it doesn't handle attributes or UDAs. The 
use of stringof is also a red flag - the same name can apply to 
different types in different scopes, and aliases may confuse 
it. Here's a version that solves both of those issues:



import std.array : join;
import std.meta : ApplyLeft, staticMap, Filter, Alias;
import std.traits;

enum isPublic(alias overload) = Alias!(__traits(getProtection, 
overload) == "public");


interface InterfaceFromClass(T, alias filter = isPublic)
{
static foreach (overload; Filter!(filter, 
staticMap!(ApplyLeft!(MemberFunctionsTuple, T), 
__traits(derivedMembers, T
mixin("@(__traits(getAttributes, overload)) 
"~attributes!overload~" ReturnType!overload 
"~__traits(identifier, overload)~"(Parameters!overload);");

}

string attributes(alias overload)()
{
enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, 
overload),
"pure", "nothrow", "ref", "@property", "@trusted", 
"@safe", "@nogc", "@system", "const", "immutable", "inout", 
"shared", "return", "scope");

return [attrs].join(" ");
}

alias A = InterfaceFromClass!C;

abstract class C : A
{
int n;
@("InterfaceMembers")
{
@(3) ref int foo(ref int a) { return n; }
@(19) @safe void bar() { }
}
}

// https://issues.dlang.org/show_bug.cgi?id=18915
// class D : C {}

static assert([__traits(allMembers, A)] == ["foo", "bar"]);
static assert(functionAttributes!(A.foo) == 
functionAttributes!(C.foo));
static assert(functionAttributes!(A.bar) == 
functionAttributes!(C.bar));

static assert(is(Parameters!(A.foo) == Parameters!(C.foo)));
static assert(is(Parameters!(A.bar) == Parameters!(C.bar)));

Note the link to issue 18915 (that's your 'string mixin output 
works...' post). I believe if we can fix that, the above should 
work.


--
  Simen


Yeah! with a little work you can include fields in the 
interfacemembers because they will be ignored.


I see no reason to have to declare an interface in D except in 
rare occasions! One should be able to abstract out an interface 
from a class or abstract class and use it as the base only for 
others to use. If a program was "sealed" there would be no real 
point in using interfaces(assuming it was designed to perfection) 
except to get around the diamond problem, which is what 
interfaces solve but in the process have forced us to duplicate 
code.


The above technique alleviates that problem greatly. It's still 
bring the members inside the interface because it allows one to 
add final, static, and normal members if desired, although, this 
can be done by using another interface and inheriting from that.




Re: Build interface from abstract class

2018-05-30 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote:
I do not think this is a problem in D. Infinite recursion can 
always be terminated with appropriate means.


1. Use attributes. methods in class A should be marked as being 
for the interface. When added to the interface they will not 
have the attribute so will not be picked up again.


2. Your method of function creation does not pick up attributes 
and other factors so it is weak.


Here is my solution that does not solve problem 2:

[Neat stuff]


Neat, but as you say it doesn't handle attributes or UDAs. The 
use of stringof is also a red flag - the same name can apply to 
different types in different scopes, and aliases may confuse it. 
Here's a version that solves both of those issues:



import std.array : join;
import std.meta : ApplyLeft, staticMap, Filter, Alias;
import std.traits;

enum isPublic(alias overload) = Alias!(__traits(getProtection, 
overload) == "public");


interface InterfaceFromClass(T, alias filter = isPublic)
{
static foreach (overload; Filter!(filter, 
staticMap!(ApplyLeft!(MemberFunctionsTuple, T), 
__traits(derivedMembers, T
mixin("@(__traits(getAttributes, overload)) 
"~attributes!overload~" ReturnType!overload 
"~__traits(identifier, overload)~"(Parameters!overload);");

}

string attributes(alias overload)()
{
enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, 
overload),
"pure", "nothrow", "ref", "@property", "@trusted", 
"@safe", "@nogc", "@system", "const", "immutable", "inout", 
"shared", "return", "scope");

return [attrs].join(" ");
}

alias A = InterfaceFromClass!C;

abstract class C : A
{
int n;
@("InterfaceMembers")
{
@(3) ref int foo(ref int a) { return n; }
@(19) @safe void bar() { }
}
}

// https://issues.dlang.org/show_bug.cgi?id=18915
// class D : C {}

static assert([__traits(allMembers, A)] == ["foo", "bar"]);
static assert(functionAttributes!(A.foo) == 
functionAttributes!(C.foo));
static assert(functionAttributes!(A.bar) == 
functionAttributes!(C.bar));

static assert(is(Parameters!(A.foo) == Parameters!(C.foo)));
static assert(is(Parameters!(A.bar) == Parameters!(C.bar)));

Note the link to issue 18915 (that's your 'string mixin output 
works...' post). I believe if we can fix that, the above should 
work.


--
  Simen


Re: Build interface from abstract class

2018-05-29 Thread DigitalDesigns via Digitalmars-d-learn

On Wednesday, 30 May 2018 at 01:46:30 UTC, Chameleon wrote:

On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote:



Here is my solution that does not solve problem 2:


import std.stdio;

[...]



this is not programming. this is witchcraft!



Just call me Dandalf the D Slayer!

At least I finally got it to work. It's terrible that I have to 
use import and read the file in directly to do this ;/ It is 
working though.


Re: Build interface from abstract class

2018-05-29 Thread Chameleon via Digitalmars-d-learn

On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote:



Here is my solution that does not solve problem 2:


import std.stdio;

[...]



this is not programming. this is witchcraft!



Re: Build interface from abstract class

2018-05-29 Thread DigitalDesigns via Digitalmars-d-learn

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  
: "
			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.





Re: Build interface from abstract class

2018-05-29 Thread DigitalDesigns via Digitalmars-d-learn

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...


Re: Build interface from abstract class

2018-05-29 Thread arturg via Digitalmars-d-learn

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);
}


Re: Build interface from abstract class

2018-05-29 Thread DigitalDesigns via Digitalmars-d-learn

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
{

}

I could see that D wants A so it can have the complete picture 
for B, but this is one of those problems where it shouldn't 
matter.



This requires hoops and ultimately does not solve the problem. 
Any time A is used it will be treated as undefined by the 
compiler and throw an error.


For example:




pragma(msg, InterfaceFromClass!(C, "A"));

mixin(InterfaceFromClass!(C, "A"));

interface B : A
{

}

abstract class C
{
@("InterfaceMembers")
{
int xe = 3;
@(3) void foo() { }

@property int x() { return 3; };

B bar() { return null; }
}

}

abstract class D : C, B
{

}

fails because C.bar returns a B, which has not yet fully been 
defined because A has not yet fully been defined. Now, if I could 
just get the function signature without using the type system, 
this wouldn't be a problem. I don't really care if B is defined 
yet, I just need to know it's name. I guess D tries to enforce 
consistency at all steps, which is a problem here because C uses 
a yet to be defined type, even though it will be defined soon 
enough without problems.


One of the main culprits is isCallable which is what errors out 
because of the yet to be defined B.


So, I guess some other method will have to work.




Re: Build interface from abstract class

2018-05-28 Thread arturg via Digitalmars-d-learn

this might help you,
https://dpaste.dzfl.pl/2cf844a11e3f

you can use them to generate the functions as strings.


Re: Build interface from abstract class

2018-05-28 Thread DigitalDesigns via Digitalmars-d-learn

On Monday, 28 May 2018 at 11:51:20 UTC, Simen Kjærås wrote:

On Monday, 28 May 2018 at 09:59:50 UTC, DigitalDesigns wrote:

Implementing interfaces can be a pain but are necessary.

I like to use abstract classes and provide a base 
implementation. It would be cool if I could use D's awesome 
meta features to extract the interface from the abstract class 
then build it. This requires some funky stuff which I'm not 
sure D can do


Creating an interface based on a class is no big deal in D:

interface Interface(T)
{
import std.traits;
static foreach (fn; __traits(allMembers, T))
static foreach (overload; MemberFunctionsTuple!(T, fn))
mixin("ReturnType!overload 
"~fn~"(Parameters!overload);");

}

class A
{
   void fun() {}
}

alias IA = Interface!A;

However, you run into a problem when A is expected to implement 
IA: in order to figure out which functions should be in the 
interface, we need to know which functions are in A. And in 
order to figure out which functions are in A, we need to know 
which functions are in IA. It's a loop with no real solution.


In this specific case, one could consider only members of A, 
ignoring any interfaces or base classes. This isn't currently 
possible, but it's not an entirely unreasonable enhancement 
request.


--
  Simen


I do not think this is a problem in D. Infinite recursion can 
always be terminated with appropriate means.


1. Use attributes. methods in class A should be marked as being 
for the interface. When added to the interface they will not have 
the attribute so will not be picked up again.


2. Your method of function creation does not pick up attributes 
and other factors so it is weak.



Case 1 should be easy to deal with. Case 2, I am not so sure how 
to build the signature exactly as it is expressed. This is, of 
course, just a copy an paste mechanism but it would require D to 
provide us the signature in some way.


Maybe an easy and direct way would be to pass __FILE__ and 
__LINE__ and extract the line? This seems a bit risky and slow.


Case 1 Will not work if UDA's are required to be exactly the same 
between interface and class. I do not know if D enforces that but 
if it does it seems a bit overkill.



Here is my solution that does not solve problem 2:


import std.stdio;



template InterfaceFromClass(alias T, string id)
{
auto InterfaceFromClass()
{
string s;
import std.traits;
foreach (member; __traits(allMembers, T))
{
static foreach (overload; MemberFunctionsTuple!(T, 
member))
{
enum attr = __traits(getAttributes, overload);
static if (__traits(getProtection, __traits(getMember, T, 
member)) == "public")

{
	mixin(`enum attrs = __traits(getAttributes, T.` ~ member ~ 
`);`);

foreach(a; attrs)
		static if (is(typeof(a) == string) && a.length > 0 && a == 
"InterfaceMembers")

{   

			s ~= (ReturnType!overload).stringof ~" 
"~member~""~(Parameters!overload).stringof~";";

}
}
}
}

return "interface "~id~"\n{\n "~s~"\n}";
}
}



Which you can see it at work here: 
https://dpaste.dzfl.pl/f49be5dd7daa


Re: Build interface from abstract class

2018-05-28 Thread Simen Kjærås via Digitalmars-d-learn

On Monday, 28 May 2018 at 09:59:50 UTC, DigitalDesigns wrote:

Implementing interfaces can be a pain but are necessary.

I like to use abstract classes and provide a base 
implementation. It would be cool if I could use D's awesome 
meta features to extract the interface from the abstract class 
then build it. This requires some funky stuff which I'm not 
sure D can do


Creating an interface based on a class is no big deal in D:

interface Interface(T)
{
import std.traits;
static foreach (fn; __traits(allMembers, T))
static foreach (overload; MemberFunctionsTuple!(T, fn))
mixin("ReturnType!overload 
"~fn~"(Parameters!overload);");

}

class A
{
   void fun() {}
}

alias IA = Interface!A;

However, you run into a problem when A is expected to implement 
IA: in order to figure out which functions should be in the 
interface, we need to know which functions are in A. And in order 
to figure out which functions are in A, we need to know which 
functions are in IA. It's a loop with no real solution.


In this specific case, one could consider only members of A, 
ignoring any interfaces or base classes. This isn't currently 
possible, but it's not an entirely unreasonable enhancement 
request.


--
  Simen