digitalmars.D.learn - Reflection magic: function signatures
- Christopher Wright (58/58) Jun 30 2007 Hey,
- Jarrett Billingsley (12/23) Jun 30 2007 But.. but you did this:
- Christopher Wright (2/32) Jun 30 2007 My god, you're a genius!
- Jarrett Billingsley (12/13) Jun 30 2007 No, D's just amazing ;) And I'm writing a library for my scripting lang...
Hey, I've been fooling around with the idea of creating a mocks library. The important thing that I need to do to get that is to create functions that can be swapped in for any functions that the mocked class or interface has. If I could implicitly cast primitives to objects, I could just write one variadic function taking a series of Objects. (I'd have to write a template to create a bunch of them that I could distinguish, but that's a minor issue.) If I could create functions at runtime, I could just go with runtime everything. But that's not possible in a compiled language. (Or at least, it'd be extremely ugly, and not widely useful, so the compiler cruft wouldn't be worth it. In interpreted languages, the compiler cruft is much smaller, so it's worth it.) I could try using templates to manufacture all reasonable function prototypes, but even assuming that I can safely and implicitly cast everything to real or Object, that's going to be O(2**n) functions to create to support n arguments. Moreover, that still only supports functions of a constant length. If I could do opImplicitCast_r and provide an argument corresponding to the type to cast from, well, that would allow me to autobox all arguments and just use varargs to handle everything. opAssign isn't used for function arguments, or else Bob'd be my uncle. As far as I can tell, I can't suss out a function signature at compile time with the current reflection systems. Flectioned seems to require a pointer to the function, and that won't exist until the function has been compiled. The best I can do is something like: --- RandomClass mock = Mock!(RandomClass); // don't use auto or badness results Expect.Call(&(mock.method)).Arguments!(3, some_object, 9.2f); --- Then I'd have to use the Arguments template (provided the arguments are CTFE-friendly) to get the types and create a valid overload. But what if the arguments aren't valid at compile time? --- RandomClass mock = Mock!(RandomClass); // don't use auto or badness results Expect.Call(&(mock.method)).Overload!(int, SomeClass, float).Arguments(3, some_object, 9.2f).ReturnType!(int).Return(4); Mocks.Replay(); // functions are actually reassigned here --- In this case, creating the functions should be simple enough: --- T function (U) CreateFunction(T, U...)() { T func(U u) { return T.init; } // probably just does first element; need mixin return &func; } --- At this point, at runtime, I have to use Flectioned to find the method to overwrite, and I can then tell the person whether they got the mock's signature right. This means that the compiler can't warn the user when something goes wrong. That's not a good thing, but I can write that code myself, if I have to. But it delays warnings and increases time to finding errors. Any suggestions as to finding a function signature at compile time? That would be the best solution. Thanks!
Jun 30 2007
"Christopher Wright" <dhasenan gmail.com> wrote in message news:f65pa1$1rt3$1 digitalmars.com...As far as I can tell, I can't suss out a function signature at compile time with the current reflection systems. Flectioned seems to require a pointer to the function, and that won't exist until the function has been compiled.But.. but you did this:--- T function (U) CreateFunction(T, U...)() { T func(U u) { return T.init; } // probably just does first element; need mixin return &func; } ---The function signature is just the return type + parameter type tuple, no? import std.traits; T function(U) CreateFunction(FuncType, T = ReturnType!(FuncType), U = ParameterTypeTuple!(FuncType))() { // static so we can return it static T func(U u) { return T.init; } return &func; }
Jun 30 2007
Jarrett Billingsley wrote:"Christopher Wright" <dhasenan gmail.com> wrote in message news:f65pa1$1rt3$1 digitalmars.com...My god, you're a genius!As far as I can tell, I can't suss out a function signature at compile time with the current reflection systems. Flectioned seems to require a pointer to the function, and that won't exist until the function has been compiled.But.. but you did this:--- T function (U) CreateFunction(T, U...)() { T func(U u) { return T.init; } // probably just does first element; need mixin return &func; } ---The function signature is just the return type + parameter type tuple, no? import std.traits; T function(U) CreateFunction(FuncType, T = ReturnType!(FuncType), U = ParameterTypeTuple!(FuncType))() { // static so we can return it static T func(U u) { return T.init; } return &func; }
Jun 30 2007
"Christopher Wright" <dhasenan gmail.com> wrote in message news:f66s11$11t4$1 digitalmars.com...My god, you're a genius!No, D's just amazing ;) And I'm writing a library for my scripting language now to automatically generate shim functions to make it easier to bind native functions to the scripting interpreter. It's heavily inspired by Pyd (www.dsource.org/projects/pyd), which does a lot of what you seem to want to do, so you can have a look at that for some more function wrapping examples. Or, you know, look at my library too (www.dsource.org/projects/minid, look in trunk/minid/bind.d in the repo). BTW when you use a type tuple (either a T... parameter ot something like the result of ParameterTypeTuple) as a parameter list or so, it does use all the elements, no mixins required.
Jun 30 2007