digitalmars.D - A thought for template alias parameters?
- Trip Volpe (30/30) Feb 03 2010 I'm working on a set of handy unit testing accessories for my projects. ...
- Joel Anderson (8/38) Feb 03 2010 You could potentially use a mixin to do this. The resulting code would
- Trip Volpe (4/13) Feb 03 2010 Yeah, mixins could work, but they're ugly. ;-)
- Joel Anderson (3/16) Feb 03 2010 That's one of the reasons I've wished D had a nicer syntax for the
- Trip Volpe (4/7) Feb 04 2010 What kind of syntax do you have in mind?
- Joel Anderson (11/18) Feb 05 2010 Not sure. I'm sure there's a syntax that could meet both goals.
- Joel Anderson (10/33) Feb 05 2010 I mean:
- Lutger (5/27) Feb 06 2010 This syntax should be possible, which also gives syntax highlighting:
- Trip Volpe (20/28) Feb 14 2010 Template alias parameters handle it nicely right now, at least in the ca...
I'm working on a set of handy unit testing accessories for my projects. What I'd love to achieve is something like this: expectEqual( myFoo, 3 ); Which, on failure, would result in something along the lines of this diagnostic: somefile.d:37: Test failure! Expected: myFoo == 3 Actual: 100, 3 Using a bit of template magic with alias parameters, I've come close: void expectEquals(alias A, alias B) ( string file = __FILE__, int line = __LINE__ ) { if(A != B) { writefln( "Error: %s, line %d", file, line ); writefln( " expected: %s == % s", A.stringof, B.stringof ); writefln( " actual: %s, %s", A, B ); } } void main() { int myFoo = 100; expectEquals! ( myFoo, 3 ); } This will produce the output Error: test.d, line 33 expected: myFoo == 3 actual: 100, 3 Unfortunately, this isn't quite there yet. Alias parameters can only match single symbols, so something like this won't compile: int myFoo = 100; int myArray[5]; expectEquals! ( myFoo, myArray[0] ); So my question is, would it be a good idea to add the ability in future versions for template parameters to alias entire expressions? It would be perfect for making templated assertions like this and probably has many other metaprogramming applications. As a recent convert from C++, I still miss the ability of macro systems (like GoogleTest) to print highly reflective unit test assertion messages. Would there be any drawbacks or difficulties in doing this that I'm completely missing? :-P
Feb 03 2010
On 2/3/2010 9:34 PM, Trip Volpe wrote:I'm working on a set of handy unit testing accessories for my projects. What I'd love to achieve is something like this: expectEqual( myFoo, 3 ); Which, on failure, would result in something along the lines of this diagnostic: somefile.d:37: Test failure! Expected: myFoo == 3 Actual: 100, 3 Using a bit of template magic with alias parameters, I've come close: void expectEquals(alias A, alias B) ( string file = __FILE__, int line = __LINE__ ) { if(A != B) { writefln( "Error: %s, line %d", file, line ); writefln( " expected: %s == % s", A.stringof, B.stringof ); writefln( " actual: %s, %s", A, B ); } } void main() { int myFoo = 100; expectEquals! ( myFoo, 3 ); } This will produce the output Error: test.d, line 33 expected: myFoo == 3 actual: 100, 3 Unfortunately, this isn't quite there yet. Alias parameters can only match single symbols, so something like this won't compile: int myFoo = 100; int myArray[5]; expectEquals! ( myFoo, myArray[0] ); So my question is, would it be a good idea to add the ability in future versions for template parameters to alias entire expressions? It would be perfect for making templated assertions like this and probably has many other metaprogramming applications. As a recent convert from C++, I still miss the ability of macro systems (like GoogleTest) to print highly reflective unit test assertion messages. Would there be any drawbacks or difficulties in doing this that I'm completely missing? :-PYou could potentially use a mixin to do this. The resulting code would look something like this. void main() { int myFoo = 100; mixin(expectEquals! ( "myFoo == 3" )); }
Feb 03 2010
Joel Anderson Wrote:You could potentially use a mixin to do this. The resulting code would look something like this. void main() { int myFoo = 100; mixin(expectEquals! ( "myFoo == 3" )); }Yeah, mixins could work, but they're ugly. ;-) Forcing the user (in this case the unit test writer) to apply extra boilerplate on their own every time they want to make an assertion is really not much of a solution. There's no semantic reason an assertion should involve a mixin, so allowing that detail to bleed into client code is shaky design. I know I'd get tired of wrapping everything in mixin(...) all the time, and in the end it would probably result in me writing fewer unit tests. :-P
Feb 03 2010
On 2/3/2010 10:27 PM, Trip Volpe wrote:Joel Anderson Wrote:That's one of the reasons I've wished D had a nicer syntax for the string mixin format. This one kinda scares people away :pYou could potentially use a mixin to do this. The resulting code would look something like this. void main() { int myFoo = 100; mixin(expectEquals! ( "myFoo == 3" )); }Yeah, mixins could work, but they're ugly. ;-) Forcing the user (in this case the unit test writer) to apply extra boilerplate on their own every time they want to make an assertion is really not much of a solution. There's no semantic reason an assertion should involve a mixin, so allowing that detail to bleed into client code is shaky design. I know I'd get tired of wrapping everything in mixin(...) all the time, and in the end it would probably result in me writing fewer unit tests. :-P
Feb 03 2010
Joel Anderson Wrote:That's one of the reasons I've wished D had a nicer syntax for the string mixin format. This one kinda scares people away :pWhat kind of syntax do you have in mind? Making mixins less obtrusive might ease aggravation when they're being used as boilerplate, but making it harder to see when they're being used might have downsides as well. :-P For a case like this, though, I still think the best solution would be to allow for template parameters that can alias whole expressions. Together with the other compile-time reflection abilities of D, I think it would make quite a powerful tool.
Feb 04 2010
On 2/4/2010 4:41 PM, Trip Volpe wrote:Joel Anderson Wrote:Not sure. I'm sure there's a syntax that could meet both goals. Something like. void expectsEquals(string data)() { mixin(data); } ... expectsEquals!("myFoo == 3")(); or expectsEquals!("myFoo == 3");That's one of the reasons I've wished D had a nicer syntax for the string mixin format. This one kinda scares people away :pWhat kind of syntax do you have in mind? Making mixins less obtrusive might ease aggravation when they're being used as boilerplate, but making it harder to see when they're being used might have downsides as well. :-PFor a case like this, though, I still think the best solution would be to allow for template parameters that can alias whole expressions. Together with the other compile-time reflection abilities of D, I think it would make quite a powerful tool.
Feb 05 2010
On 2/5/2010 8:55 PM, Joel Anderson wrote:On 2/4/2010 4:41 PM, Trip Volpe wrote:I mean: void expectsEquals(string data)() { mixin(dostuff(data)); } ... expectsEquals!("myFoo == 3")(); or expectsEquals!("myFoo == 3");Joel Anderson Wrote:Not sure. I'm sure there's a syntax that could meet both goals. Something like. void expectsEquals(string data)() { mixin(data); }That's one of the reasons I've wished D had a nicer syntax for the string mixin format. This one kinda scares people away :pWhat kind of syntax do you have in mind? Making mixins less obtrusive might ease aggravation when they're being used as boilerplate, but making it harder to see when they're being used might have downsides as well. :-PFor a case like this, though, I still think the best solution would be to allow for template parameters that can alias whole expressions. Together with the other compile-time reflection abilities of D, I think it would make quite a powerful tool.
Feb 05 2010
On 02/06/2010 05:55 AM, Joel Anderson wrote:On 2/4/2010 4:41 PM, Trip Volpe wrote:This syntax should be possible, which also gives syntax highlighting: expectEquals!q{ myFoo == 3 }; But there is the problem that expectEquals is defined in a module which doesn't have access to myFoo. I don't know how to solve that.Joel Anderson Wrote:Not sure. I'm sure there's a syntax that could meet both goals. Something like. void expectsEquals(string data)() { mixin(data); } ... expectsEquals!("myFoo == 3")(); or expectsEquals!("myFoo == 3");That's one of the reasons I've wished D had a nicer syntax for the string mixin format. This one kinda scares people away :pWhat kind of syntax do you have in mind? Making mixins less obtrusive might ease aggravation when they're being used as boilerplate, but making it harder to see when they're being used might have downsides as well. :-P
Feb 06 2010
Lutger Wrote:This syntax should be possible, which also gives syntax highlighting: expectEquals!q{ myFoo == 3 }; But there is the problem that expectEquals is defined in a module which doesn't have access to myFoo. I don't know how to solve that.Template alias parameters handle it nicely right now, at least in the case where you only need to use a single symbol and not a compound expression: In mycontracts.d: void expectEqual(alias A, alias B) ( string file = __FILE__, int line = __LINE__ ) { if(A != B) { string msg = format("expected: %s==%s; actual: %s, %s", A.stringof, B.stringof, A, B ); fail( msg, file, line ); } } In somethingelse.d: expectEqual! ( myFoo, 3 ); Even where expectEqual is defined in a different module, the symbol myFoo is still evaluated in the correct context (the context in which expectEqual is being instantiated). What I'm suggesting is that alias parameters be expanded to allow compound expressions. That would allow you to also use object fields, array elements, and so forth in expectEqual, like so: expectEqual! ( foo.baz[2], 42 ); expectEqual! ( wibble(), "OK" ); You could also do expect with a single expression and no awkward boilerplate: expect! ( myFoo == 3 ); I think this would be a great enhancement; I was just curious if there's any good reason _not_ to do this that I'm not aware of. :-)
Feb 14 2010