digitalmars.D - __traits and determining all overridable functions
- Steven Schveighoffer (34/34) Nov 12 2007 Hi,
- Christopher Wright (28/72) Nov 12 2007 http://dsource.org/projects/dmocks/browser/trunk/dmocks
- Christopher Wright (6/8) Nov 12 2007 The constructor problem is solved, and I converted all my small
- Steven Schveighoffer (7/55) Nov 12 2007 Hm... good point. So the getVirtualFunctions would be a better idea.
- Steven Schveighoffer (4/10) Nov 12 2007 Is static foreach a planned feature? This sounds like it would be much
- Christopher Wright (2/15) Nov 12 2007 Yes. But not quite yet. There's a ticket for it.
- Robert Fraser (8/9) Nov 12 2007 Yes you can, in the context of a function.
- Christopher Wright (8/21) Nov 12 2007 You're right. You can use that to, say, do string manipulations based on...
Hi, I was thinking of making a template that derives from an object, but intercepts all calls to virtual functions automatically. This could be used for something like RMI or .net Remoting to allow a call to either execute a method locally or in an object on a server if connected. I thought maybe I could use __traits to determine all virtual functions, then override them using a mixin. I thought __traits was a compile-time function, and so I thought I could create a compile-time-function that returns a string defining all virtual functions. However, in doing so I find that the function does not work correctly, and in addition, the argument to __traits for isVirtualFunction does not take a string, but the result of __traits allMembers is an array of strings. I think it would be more useful if isVirtualFunction and the other isXX would take either a string or the direct statement. For example: __traits(isVirtualFunction, "A.foo") would be the same as: __traits(isVirtualFunction, A.foo) Then I could do: foreach(x; __traits(allMembers, A)) if(__traits(isVirtualfunction, "A." ~ x)) // append to string that redefines virtual function. Second, the mixin doesn't work. I hard-coded the function to output the string I was trying to build. Therefore, the compiler should be able to execute the method in compile time, and pre-determine the string to return. But the mixin just defines the function name that I am calling as a member. i.e., I define my function above as: string redefFunctions(T)(); and my mixin in the class is: mixin(redefFunctions!(A)()); But when I build my class, there is a member redefFunctions!(A) instead of the list of virtual functions I expected to override. Any ideas? Is there another way this will work? If not, is it possible to make it so it would work :) ? -Steve
Nov 12 2007
Steven Schveighoffer wrote:Hi, I was thinking of making a template that derives from an object, but intercepts all calls to virtual functions automatically. This could be used for something like RMI or .net Remoting to allow a call to either execute a method locally or in an object on a server if connected.http://dsource.org/projects/dmocks/browser/trunk/dmocks Take a look at MockObject.d and MethodMock.d -- they have pretty much everything you need. Maybe I should extract them out.... One caveat is constructors, though. Your proxied class isn't guaranteed a default constructor. You have to use, as I recall, ParameterTypeTuple!(T._ctor) to get the arguments, and supply a constructor of the appropriate type. Hm. I thought I had solved that problem in my library, but now I see I commented that test out. Bad me |:(I thought maybe I could use __traits to determine all virtual functions, then override them using a mixin. I thought __traits was a compile-time function, and so I thought I could create a compile-time-function that returns a string defining all virtual functions.It does, and it works. See above :)However, in doing so I find that the function does not work correctly, and in addition, the argument to __traits for isVirtualFunction does not take a string, but the result of __traits allMembers is an array of strings. I think it would be more useful if isVirtualFunction and the other isXX would take either a string or the direct statement. For example: __traits(isVirtualFunction, "A.foo") would be the same as: __traits(isVirtualFunction, A.foo)class A { final void foo (); int foo (int i); } What to return? __traits(isVirtualFunction, A.foo) is ambiguous as well. I don't recommend using it, and I don't use it.Then I could do: foreach(x; __traits(allMembers, A)) if(__traits(isVirtualfunction, "A." ~ x)) // append to string that redefines virtual function.You can't foreach an array at compile time, and __traits(allMembers) returns an array. You can index an array at compile time, but again, you can't use a while loop at compile time. You have to use recursion. Eventually, static foreach should be able to do this. Or you can bug Walter about changing allMembers to return a tuple of strings.Second, the mixin doesn't work. I hard-coded the function to output the string I was trying to build. Therefore, the compiler should be able to execute the method in compile time, and pre-determine the string to return. But the mixin just defines the function name that I am calling as a member. i.e., I define my function above as: string redefFunctions(T)(); and my mixin in the class is: mixin(redefFunctions!(A)()); But when I build my class, there is a member redefFunctions!(A) instead of the list of virtual functions I expected to override.Not sure what the problem there is. If you omit the parentheses around the template method call, you'll definitely get the result you describe (that had me hung up for a bit), but your example has the parentheses.Any ideas? Is there another way this will work? If not, is it possible to make it so it would work :) ? -SteveGood luck!
Nov 12 2007
Christopher Wright wrote:Hm. I thought I had solved that problem in my library, but now I see I commented that test out. Bad me |:(The constructor problem is solved, and I converted all my small integration tests into large integration tests (that is, instead of testing half the code with each test, they test all the code -- better than nothing). But that isn't a great feat, once you have the rest.
Nov 12 2007
"Christopher Wright" wrotehttp://dsource.org/projects/dmocks/browser/trunk/dmocks Take a look at MockObject.d and MethodMock.d -- they have pretty much everything you need. Maybe I should extract them out....Excellent work! I think this is exactly what I was looking for.Hm... good point. So the getVirtualFunctions would be a better idea.However, in doing so I find that the function does not work correctly, and in addition, the argument to __traits for isVirtualFunction does not take a string, but the result of __traits allMembers is an array of strings. I think it would be more useful if isVirtualFunction and the other isXX would take either a string or the direct statement. For example: __traits(isVirtualFunction, "A.foo") would be the same as: __traits(isVirtualFunction, A.foo)class A { final void foo (); int foo (int i); } What to return? __traits(isVirtualFunction, A.foo) is ambiguous as well. I don't recommend using it, and I don't use it.Aha! this is what I was missing :)Then I could do: foreach(x; __traits(allMembers, A)) if(__traits(isVirtualfunction, "A." ~ x)) // append to string that redefines virtual function.You can't foreach an array at compile time, and __traits(allMembers) returns an array. You can index an array at compile time, but again, you can't use a while loop at compile time. You have to use recursion.Eventually, static foreach should be able to do this. Or you can bug Walter about changing allMembers to return a tuple of strings.Not sure either :) But enough about my horribly disfigured abortion of code, I think I'll just base my stuff off of your Mock Objects lib :) -SteveSecond, the mixin doesn't work. I hard-coded the function to output the string I was trying to build. Therefore, the compiler should be able to execute the method in compile time, and pre-determine the string to return. But the mixin just defines the function name that I am calling as a member. i.e., I define my function above as: string redefFunctions(T)(); and my mixin in the class is: mixin(redefFunctions!(A)()); But when I build my class, there is a member redefFunctions!(A) instead of the list of virtual functions I expected to override.Not sure what the problem there is. If you omit the parentheses around the template method call, you'll definitely get the result you describe (that had me hung up for a bit), but your example has the parentheses.
Nov 12 2007
"Christopher Wright" wroteYou can't foreach an array at compile time, and __traits(allMembers) returns an array. You can index an array at compile time, but again, you can't use a while loop at compile time. You have to use recursion. Eventually, static foreach should be able to do this. Or you can bug Walter about changing allMembers to return a tuple of strings.Is static foreach a planned feature? This sounds like it would be much preferrable to the recursion. -Steve
Nov 12 2007
Steven Schveighoffer wrote:"Christopher Wright" wroteYes. But not quite yet. There's a ticket for it.You can't foreach an array at compile time, and __traits(allMembers) returns an array. You can index an array at compile time, but again, you can't use a while loop at compile time. You have to use recursion. Eventually, static foreach should be able to do this. Or you can bug Walter about changing allMembers to return a tuple of strings.Is static foreach a planned feature? This sounds like it would be much preferrable to the recursion.
Nov 12 2007
Christopher Wright Wrote:You can't foreach an array at compile time [...]Yes you can, in the context of a function. string ct_func(string[] arr) { foreach(s; arr) { ... } } mixin(ct_func(__traits(allMembers, Foo)));
Nov 12 2007
Robert Fraser wrote:Christopher Wright Wrote:You're right. You can use that to, say, do string manipulations based on a string array. However, you cannot use these strings with pragmas or __traits. I had tried using foreach on __traits(allMembers) in my code, but since I went on to do __traits(getVirtualFunctions) using those strings, dmd wasn't happy with me. :`( That's why I use recursive templates in my code.You can't foreach an array at compile time [...]Yes you can, in the context of a function. string ct_func(string[] arr) { foreach(s; arr) { ... } } mixin(ct_func(__traits(allMembers, Foo)));
Nov 12 2007