Thread: RE: [Cppunit-devel] CppUnit 1.8.0 features...
Brought to you by:
blep
From: Summerwill, B. <BSu...@eu...> - 2001-09-25 11:19:25
|
Baptiste wrote: >> I would actually call that one a bug fix. While const is usefull when >> manipulating value object, it is a strong constraint. Personnaly, I have taken >> Michael Feather's advice on XP and C++ and don't use const on reference object >> (object who don't have public copy constructor). This make refactoring a lot >> easier, but writing assertion_traits black magic :-(. Please could you clarify why you wouldn't want const references? Maybe provide a link to Michael Feather's advice? I've always found const-correctness very useful, and would see removing const-correctness from CppUnit as a backwards step. There are a number of other areas in the framework which I spotted as not being const-correct. Is this a policy decision, that you aren't being const-correct? Cheers, Bob -----Original Message----- From: Baptiste Lepilleur [mailto:gai...@fr...] Sent: 25 September 2001 11:40 To: Baptiste Lepilleur Cc: Cpp Unit Develpment Mailing List Subject: Re: [Cppunit-devel] CppUnit 1.8.0 features... Quoting Baptiste Lepilleur <bl...@cl...>: > Depending on how soon you want 1.8.0 to be, here is a list of > feature > that are simple to implement: > > 1) CPPUNIT_TEST_EXCEPTION( method, ExceptionType) > 2) CPPUNIT_TEST_FAIL( method ) > 3) add a flag to TestFailure distinguishing error/failure, retain > only > one collection to store result > (see other mail) > 4) CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( TestFixtureType, SuiteName > ) : > register the fixture's suite in a suite of the specified name. > 5) Qt TestRunner (I've got it working, need feedback and help to > use > TMAKE to build a library instead of an application) > 6) ASSERT_EQUAL support for two differents compatible types 7) remove consteness on ASSERT_EQUAL. I would actually call that one a bug fix. While const is usefull when manipulating value object, it is a strong constraint. Personnaly, I have taken Michael Feather's advice on XP and C++ and don't use const on reference object (object who don't have public copy constructor). This make refactoring a lot easier, but writing assertion_traits black magic :-(. Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French _______________________________________________ Cppunit-devel mailing list Cpp...@li... https://lists.sourceforge.net/lists/listinfo/cppunit-devel |
From: Baptiste L. <gai...@fr...> - 2001-09-25 12:19:30
|
Quoting Volker Boerchers <boe...@we...>: > On Tue, 25 Sep 2001, Baptiste Lepilleur wrote: > > > Quoting Baptiste Lepilleur <bl...@cl...>: > > > > 7) remove consteness on ASSERT_EQUAL. > > I would actually call that one a bug fix. While const is usefull > when > > manipulating value object, it is a strong constraint. Personnaly, I > have taken > > Michael Feather's advice on XP and C++ and don't use const on > reference object > > (object who don't have public copy constructor). This make refactoring > a lot > > easier, but writing assertion_traits black magic :-(. > > Hi Baptiste, > > could you give me a reference on this subject, some online docs or so > - > This advice is new to me. This is part the extreme programming challenges: http://c2.com/cgi/wiki?ExtremeProgrammingChallenge and the more specifically the C++ challenge (the page you're interested in): http://c2.com/cgi/wiki?ExtremeProgrammingChallengeSeven The comment is very short, but my current working rules are: 1) avoid pass-by-value or non const reference, prefer pointer => allow polymorphism 2) prefer pass-by-value to const reference => don't need to had "const" method to object. 3) avoid to return const reference, prefer return by value => the former make it difficult to change the implementation 4) never use const method. => const is often more an hinderance that help when refactoring. I still don't realy know what to do about non const reference. I usually avoid them (so reference are only use as optimisation to pass-by-value), but it sometimes lead to clumsy code (pointer on std::vector)... I still haven't got around using the make everything virtual, but adding the virtuality when needed is not a problem. Part of those rules where inferred from Michael Feather's CppUnit. And we still haven't our refactoring catalog (we have multiple inheritance and template)... Baptiste. > > Thanks and > Thanks for your work on cppunit! > Volker > -- > Volker Boerchers, boe...@we... > > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Summerwill, B. <BSu...@eu...> - 2001-09-25 13:10:29
|
I personally disagree with lots of these comments, as do lots of other people, whose comments you can see if you follow some of the links from these Wiki pages (see UseConstMemberFunctions and ConstCorrectness). Specifically ... 1. Make all member functions virtual unless there is a compelling need not too. ---------------------------------------------------------------------------- --- I can't agree with this. If you need to subclass something, and override a method, you should make the method virtual _when you need to_. Otherwise it's just a case of YouArentGoingToNeedIt. The code will run slower for no real gain. 2. Make all functions public. ----------------------------- As covered in some of the WikiWeb pages, this actually makes refactoring harder, because it breaks encapsulation. 3. Avoid const on members ------------------------- In my experience, having const-correct members doesn't make refactoring harder. It does restrict your code, but this is in a good way. The compiler is making additional checks that your code is doing what you expect. 4. Have uniform conventions --------------------------- I absolutely agree with this. Following up your comments, Baptiste ... >> 1) avoid pass-by-value or non const reference, prefer pointer >> => allow polymorphism Yes. >> 2) prefer pass-by-value to const reference >> => don't need to had "const" method to object. If the object you're passing to a method isn't const-correct, then you'll obviously need to do this. >> 3) avoid to return const reference, prefer return by value >> => the former make it difficult to change the implementation Not sure I agree with that. I think it probably varies by class. >> 4) never use const method. >> => const is often more an hinderance that help when refactoring. Disagree. I'd urge you to read more fully through all the follow-up comments to Michael's posting before making any changes. What does everyone else think? Cheers, Bob -----Original Message----- From: Baptiste Lepilleur [mailto:gai...@fr...] Sent: 25 September 2001 13:19 To: Cpp Unit Develpment Mailing List Subject: Re: [Cppunit-devel] CppUnit 1.8.0 features... Quoting Volker Boerchers <boe...@we...>: > On Tue, 25 Sep 2001, Baptiste Lepilleur wrote: > > > Quoting Baptiste Lepilleur <bl...@cl...>: > > > > 7) remove consteness on ASSERT_EQUAL. > > I would actually call that one a bug fix. While const is usefull > when > > manipulating value object, it is a strong constraint. Personnaly, I > have taken > > Michael Feather's advice on XP and C++ and don't use const on > reference object > > (object who don't have public copy constructor). This make refactoring > a lot > > easier, but writing assertion_traits black magic :-(. > > Hi Baptiste, > > could you give me a reference on this subject, some online docs or so > - > This advice is new to me. This is part the extreme programming challenges: http://c2.com/cgi/wiki?ExtremeProgrammingChallenge and the more specifically the C++ challenge (the page you're interested in): http://c2.com/cgi/wiki?ExtremeProgrammingChallengeSeven The comment is very short, but my current working rules are: 1) avoid pass-by-value or non const reference, prefer pointer => allow polymorphism 2) prefer pass-by-value to const reference => don't need to had "const" method to object. 3) avoid to return const reference, prefer return by value => the former make it difficult to change the implementation 4) never use const method. => const is often more an hinderance that help when refactoring. I still don't realy know what to do about non const reference. I usually avoid them (so reference are only use as optimisation to pass-by-value), but it sometimes lead to clumsy code (pointer on std::vector)... I still haven't got around using the make everything virtual, but adding the virtuality when needed is not a problem. Part of those rules where inferred from Michael Feather's CppUnit. And we still haven't our refactoring catalog (we have multiple inheritance and template)... Baptiste. > > Thanks and > Thanks for your work on cppunit! > Volker > -- > Volker Boerchers, boe...@we... > > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French _______________________________________________ Cppunit-devel mailing list Cpp...@li... https://lists.sourceforge.net/lists/listinfo/cppunit-devel |
From: Baptiste L. <gai...@fr...> - 2001-09-25 13:59:42
|
Quoting "Summerwill, Bob" <BSu...@eu...>: > I personally disagree with lots of these comments, as do lots of other > people, whose comments you can see if you follow some of the links > from these Wiki pages (see UseConstMemberFunctions and > ConstCorrectness). > > > Specifically ... > > > 1. Make all member functions virtual unless there is a compelling need > not too. > ---------------------------------------------------------------------------- > I can't agree with this. If you need to subclass something, and override a > method, you should make the method virtual _when you need to_. Otherwise > it's just a case of YouArentGoingToNeedIt. The code will run slower for no > real gain. Like I said, I'd rather go back and add virtuality. > 2. Make all functions public. > ----------------------------- > As covered in some of the WikiWeb pages, this actually makes refactoring > harder, because it breaks encapsulation. Kinda weird, I actually read "think long and hard before making a function public"... Well, I agree. I usually make everything private. On the otherhand, I tend to pull private method and raise them to public/protected access if I fill the need to (though I might rethink the interface at the time). > 3. Avoid const on members > ------------------------- > In my experience, having const-correct members doesn't make > refactoring > harder. It does restrict your code, but this is in a good way. The > compiler is making additional checks that your code is doing what you > expect. Well, when I apply the "rules" I gave, you don't have much "const" remaining. I make thing simpler (though for value object, you usually end-up providing constness to be compatible with existing library (STL)). I prefer to pull up the Immutable pattern when I need "constness". Often, const get in my way, and I would end-up with many attributs being mutable. My guess is that it depends on the way your style of code. All I know is that I have applyied those rules (my version) in my development for the last 3 months (including a new project at work), and found it to work pretty well. > 4. Have uniform conventions > --------------------------- > I absolutely agree with this. Following up your comments, Baptiste > ... > > > >> 1) avoid pass-by-value or non const reference, prefer pointer > >> => allow polymorphism > > Yes. > > >> 2) prefer pass-by-value to const reference > >> => don't need to had "const" method to object. > > If the object you're passing to a method isn't const-correct, then > you'll > obviously need to do this. > > >> 3) avoid to return const reference, prefer return by value > >> => the former make it difficult to change the implementation > > Not sure I agree with that. I think it probably varies by class. My experience is that if you have: const std::vector<Test*> &getTests() You can not change your implementation to something else ( std::map<string,Test*> for example) without impacting client. But if you had: std::vector<Test*> getTests(), then it could easily be done. > I'd urge you to read more fully through all the follow-up comments to > Michael's posting before making any changes. What does everyone else > think? Does removing the constness check on assertertion_traits bother you that much ? Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-09-26 14:16:00
|
Quoting Noel Llopis <ll...@ho...>: > First time contributing to the list, but here it goes... Well, look like you hit "reply" instead of "reply all" (happen to me sometime too)... Your welcome to contribute to the list. While I found some bit of interest discussing the current topic, I would be more interested on having feedback on CppUnit design (Exception, TestFailure & co...) ;-) > > > I personally disagree with lots of these comments, as do lots of > other > > people, whose comments you can see if you follow some of the links > > from these Wiki pages (see UseConstMemberFunctions and > ConstCorrectness). > > Absolutely. I think doing that would be a big step backward I don't know if you read all the thread. CppUnit won't change in those aspect. I was just stating that CppUnit should not enforce users to respect the constness policy with their objects. [...] > I don't buy the idea that const gets in the way of refactoring. > That's right up there with saying that most functions should be > public or virtual. > > const, if anything, helps refactoring by reminding you of the > itention of the code. Isn't XP so big on self documenting code? > What better example than the compiler yelling at you because > you tried to modify something when somebody explicitely > decided that it shouldn't? If you're going to change something > as fundamental as that, you might as well remove a couple of > const statements. That's because you use const to define an "immutable" interface to your objects. I prefer to stick to pass by value, or other interface that don't provide "write" access... And you exactly stated why it may be hard to change: "somebody explicitely say that it shouldn't". Yeah, but now I need to. Accessing mutable method is my change. How hard can that be ? Find all the callers, change the reference/pointer type. Might also have to search their callers, and so on... Of course, that time "lost" making that change have to be compared to the time that the compiler would save for you. I find myself doing quite well without that belt... And not having to think about "should I pass/use a const pointer or a mutable pointer" make think easier. > > My guess is that it depends on the way your style of code. All I > > know is that I have applyied those rules (my version) in my > > development for the last 3 months (including a new project at work), > > and found it to work pretty well. > > Of course, it's all a personal preference. Some people also > like to limit themselves to the C subset when they're using C++. > I found that correctly using const (for references and member functions) > has been extremely useful for me at work and in my own code. Yup. It has to do with convention. I found those I defined to be working quite well for me. They still need some rafinment, and will evolve as everyhing does. [...] > > > >> 2) prefer pass-by-value to const reference > > > >> => don't need to had "const" method to object. > > Why would you ever want to do that? Const references have > to be the cleanest, most efficient way of passing parameters. > Why would you want to copy the whole object, so you > can modify it inside the function? If so you can always make > a local copy (although I suspect that it could be done in > a different, much more clear and efficient way). With my conventions, references are pointers and allow polymorphism. My conventions are that pointers are used for reference objects, and pass by value is used for value objects. Const references may be added in optimization phase when need to pass value object. Since most of the object I have are not value object, I mostly use pointers around (by the way, I forgot another of my rule: public methods should never return NULL pointer (the null flag bug pattern)). > > > >> 3) avoid to return const reference, prefer return by value > > > >> => the former make it difficult to change the implementation > > > > > > Not sure I agree with that. I think it probably varies by class. > > My experience is that if you have: > > const std::vector<Test*> &getTests() > > > > You can not change your implementation to something else ( > > std::map<string,Test*> for example) without impacting client. But if > you had: > > std::vector<Test*> getTests(), > > then it could easily be done. > > I don't see how that makes it any easier to update. It seems > that in both cases you need to update the type of the variable that > will receive the return value. No. If you return a vector by value, and you store the data in a map, then you can create a temporary vector that you return: sdt::vector<Test*> getTests() { std::vector<Test*> tests; for ( iterates the map ) tests.push_back(...) return tests; } > I usually follow the rule to return a const reference when possible, > and a value otherwise. The nice thing abou this is that you can > switch between the two without having to update the client code > at all. > > So const MyClass & a = something.GetA(); > will work both when a is returned by value or const reference. Beware of the "you can switch between the two at will". While the reference on a temporary is suposed to remain valid as long as the reference exist, you can run in some troubles. For example, return by value returns a mutable object ( myObject.setName( file.readLine().stripSpaces(), which is not possible with const reference ). Here is an example of unwanted behavior: (note that while it can be spoted easily there, the actual "obj.set" can occur after a long serie of method calls that would finaly call back on obj) --- #include <iostream> #include <vector> class Object { public: // std::vector<int> get() // for the correct version const std::vector<int> &get() { return _values;} void set( const std::vector<int> &values ) { _values = values; } private: std::vector<int> _values; }; void main() { Object obj; const std::vector<int> &values = obj.get(); std::vector<int> otherValues( values ); otherValues.push_back( 3 ); // change the value in obj, with const ref&, indirectly change values! obj.set( otherValues ); Object obj2; obj2.set( values ); std::cout << "obj.get() : " << obj.get().size() << std::endl << "obj2.get() : " << obj2.get().size() << std::endl; } -- and you get: obj.get() : 1 obj2.get() : 1 instead of: obj.get() : 1 obj2.get() : 0 --- Also, another source of trouble would be: const std::vector<int> &values = obj->get(); delete obj; Amazingly, values is still a valid reference. As before, the delete can occurs far away (A less likely case, I concede). So my take is that pass-by-value provide stronger isolation, and therefore make refactoring somewhat easier. Baptiste. > --Noel > ll...@ho... > > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Summerwill, B. <BSu...@eu...> - 2001-09-25 13:22:34
|
Baptiste wrote ... >> I'm not saying to change CppUnit as a whole. The only thing I want to change >> is those part of CppUnit that would impose on the "user" policy: Fair enough. Was this the result of a specific problem or bug report? Sorry if my last e-mail comes across badly. I think that the work that's been done on CppUnit in the last few months is really positive, and am just wary of large-scale changes being made, such as virtuals for everything. Cheers, Bob -----Original Message----- From: Baptiste Lepilleur [mailto:gai...@fr...] Sent: 25 September 2001 13:57 To: Summerwill, Bob Cc: Baptiste Lepilleur; Baptiste Lepilleur; Cpp Unit Develpment Mailing List Subject: RE: [Cppunit-devel] CppUnit 1.8.0 features... Quoting "Summerwill, Bob" <BSu...@eu...>: > > Baptiste wrote: > > >> I would actually call that one a bug fix. While const is usefull when > > >> manipulating value object, it is a strong constraint. Personnaly, I > have > taken > >> Michael Feather's advice on XP and C++ and don't use const on > reference > object > >> (object who don't have public copy constructor). This make > refactoring a > lot > >> easier, but writing assertion_traits black magic :-(. > > Please could you clarify why you wouldn't want const references? > Maybe > provide > a link to Michael Feather's advice? > > I've always found const-correctness very useful, and would see > removing > const-correctness from CppUnit as a backwards step. There are a number > of > other > areas in the framework which I spotted as not being const-correct. Is > this > a > policy decision, that you aren't being const-correct? See other mail for urls. Note that the framework was first written by Michael Feather, who did not use const (which explain why the constness is shacky). I'm not saying to change CppUnit as a whole. The only thing I want to change is those part of CppUnit that would impose on the "user" policy: struct assertion_traits { static bool equal( const T& x, const T& y ) => change to static bool equal( T& x, T& y ) and template <class T> void assertEquals( const T& expected, const T& actual, => change to: template <class T> void assertEquals( T& expected, T& actual, The change is invisible for user that apply the "const" policy, and allow user who don't to use the assertEquals without having to do const_cast. Baptiste. > > > Cheers, > Bob > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Summerwill, B. <BSu...@eu...> - 2001-09-25 14:10:02
|
Baptiste wrote ... >> Does removing the constness check on assertertion_traits bother >> you that much ? Not anymore, I just thought it was part of something bigger. Sorry to make a fuss ;-) Cheers, Bob -----Original Message----- From: Baptiste Lepilleur [mailto:gai...@fr...] Sent: 25 September 2001 15:00 To: cpp...@li... Subject: RE: [Cppunit-devel] CppUnit 1.8.0 features... Quoting "Summerwill, Bob" <BSu...@eu...>: > I personally disagree with lots of these comments, as do lots of other > people, whose comments you can see if you follow some of the links > from these Wiki pages (see UseConstMemberFunctions and > ConstCorrectness). > > > Specifically ... > > > 1. Make all member functions virtual unless there is a compelling need > not too. > ---------------------------------------------------------------------------- > I can't agree with this. If you need to subclass something, and override a > method, you should make the method virtual _when you need to_. Otherwise > it's just a case of YouArentGoingToNeedIt. The code will run slower for no > real gain. Like I said, I'd rather go back and add virtuality. > 2. Make all functions public. > ----------------------------- > As covered in some of the WikiWeb pages, this actually makes refactoring > harder, because it breaks encapsulation. Kinda weird, I actually read "think long and hard before making a function public"... Well, I agree. I usually make everything private. On the otherhand, I tend to pull private method and raise them to public/protected access if I fill the need to (though I might rethink the interface at the time). > 3. Avoid const on members > ------------------------- > In my experience, having const-correct members doesn't make > refactoring > harder. It does restrict your code, but this is in a good way. The > compiler is making additional checks that your code is doing what you > expect. Well, when I apply the "rules" I gave, you don't have much "const" remaining. I make thing simpler (though for value object, you usually end-up providing constness to be compatible with existing library (STL)). I prefer to pull up the Immutable pattern when I need "constness". Often, const get in my way, and I would end-up with many attributs being mutable. My guess is that it depends on the way your style of code. All I know is that I have applyied those rules (my version) in my development for the last 3 months (including a new project at work), and found it to work pretty well. > 4. Have uniform conventions > --------------------------- > I absolutely agree with this. Following up your comments, Baptiste > ... > > > >> 1) avoid pass-by-value or non const reference, prefer pointer > >> => allow polymorphism > > Yes. > > >> 2) prefer pass-by-value to const reference > >> => don't need to had "const" method to object. > > If the object you're passing to a method isn't const-correct, then > you'll > obviously need to do this. > > >> 3) avoid to return const reference, prefer return by value > >> => the former make it difficult to change the implementation > > Not sure I agree with that. I think it probably varies by class. My experience is that if you have: const std::vector<Test*> &getTests() You can not change your implementation to something else ( std::map<string,Test*> for example) without impacting client. But if you had: std::vector<Test*> getTests(), then it could easily be done. > I'd urge you to read more fully through all the follow-up comments to > Michael's posting before making any changes. What does everyone else > think? Does removing the constness check on assertertion_traits bother you that much ? Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French _______________________________________________ Cppunit-devel mailing list Cpp...@li... https://lists.sourceforge.net/lists/listinfo/cppunit-devel |
From: Baptiste L. <gai...@fr...> - 2001-09-25 15:23:34
|
Quoting "Summerwill, Bob" <BSu...@eu...>: > > Baptiste wrote ... > > >> I'm not saying to change CppUnit as a whole. The only thing I want > to > change > >> is those part of CppUnit that would impose on the "user" policy: > > Fair enough. Was this the result of a specific problem or bug report? Found that one when I started wrote an assertion_traits the other day. I was not happy with the result... > > Sorry if my last e-mail comes across badly. I think that the work > that's Sorry if it seems so, but my english tend to be a bit "rough". > been done on CppUnit in the last few months is really positive, and am > just wary of large-scale changes being made, such as virtuals for > everything. Since I probably missworded something in my previous mails, let's just make some things clear: - CppUnit has moved toward constness, and will continue to move that way. - I intend for change to have has little impact has possible - There would be no point making everything virtual in CppUnit... - I want CppUnit to impose as little constraint as possible on the user design (consteness in the user classes should be a matter of choice for example). - I intend for change being made to brough new functionality or make CppUnit easier to use (I don't like to do thing that have no 'value'). Hey Steve, Baastian, do you share my view on those points ? Pfiuuu, just escaped "Const War, the return" ;-) Baptiste. > > > Cheers, > Bob > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-09-25 12:57:00
|
Quoting "Summerwill, Bob" <BSu...@eu...>: > > Baptiste wrote: > > >> I would actually call that one a bug fix. While const is usefull when > > >> manipulating value object, it is a strong constraint. Personnaly, I > have > taken > >> Michael Feather's advice on XP and C++ and don't use const on > reference > object > >> (object who don't have public copy constructor). This make > refactoring a > lot > >> easier, but writing assertion_traits black magic :-(. > > Please could you clarify why you wouldn't want const references? > Maybe > provide > a link to Michael Feather's advice? > > I've always found const-correctness very useful, and would see > removing > const-correctness from CppUnit as a backwards step. There are a number > of > other > areas in the framework which I spotted as not being const-correct. Is > this > a > policy decision, that you aren't being const-correct? See other mail for urls. Note that the framework was first written by Michael Feather, who did not use const (which explain why the constness is shacky). I'm not saying to change CppUnit as a whole. The only thing I want to change is those part of CppUnit that would impose on the "user" policy: struct assertion_traits { static bool equal( const T& x, const T& y ) => change to static bool equal( T& x, T& y ) and template <class T> void assertEquals( const T& expected, const T& actual, => change to: template <class T> void assertEquals( T& expected, T& actual, The change is invisible for user that apply the "const" policy, and allow user who don't to use the assertEquals without having to do const_cast. Baptiste. > > > Cheers, > Bob > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Steve M. R. <ste...@vi...> - 2001-09-25 14:33:15
|
On Tue, Sep 25, 2001 at 02:56:55PM +0200, Baptiste Lepilleur wrote: > I'm not saying to change CppUnit as a whole. The only thing I want > to change is those part of CppUnit that would impose on the > "user" policy: > > struct assertion_traits > { > static bool equal( const T& x, const T& y ) > => change to > static bool equal( T& x, T& y ) > > and > template <class T> > void assertEquals( const T& expected, > const T& actual, > => change to: > template <class T> > void assertEquals( T& expected, > T& actual, > > The change is invisible for user that apply the "const" policy, and allow > user who don't to use the assertEquals without having to do const_cast. Sorry Baptiste, I do not understand. Why do you say that using const references makes writing equal() black magic? Can you give us a short example of a class that is problematic for equal(const&,const&)? I'm worried about making the change you propose. I use const a lot, and I'm sure that I have CppUnit tests in functions that are passed const references: foo( const T& x ) { T y(blahblah); CPPUNIT_ASSERT_EQUAL(x,y); } I think your proposed change would break my code, wouldn't it? Thanks, -Steve -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Baptiste L. <gai...@fr...> - 2001-09-25 15:13:38
|
Quoting "Steve M. Robbins" <ste...@vi...>: > On Tue, Sep 25, 2001 at 02:56:55PM +0200, Baptiste Lepilleur wrote: > > > I'm not saying to change CppUnit as a whole. The only thing I want > > to change is those part of CppUnit that would impose on the > > "user" policy: > > > > struct assertion_traits > > { > > static bool equal( const T& x, const T& y ) > > => change to > > static bool equal( T& x, T& y ) > > > > and > > template <class T> > > void assertEquals( const T& expected, > > const T& actual, > > => change to: > > template <class T> > > void assertEquals( T& expected, > > T& actual, > > > > The change is invisible for user that apply the "const" policy, and > allow > > user who don't to use the assertEquals without having to do > const_cast. > > Sorry Baptiste, I do not understand. Why do you say that using const > references makes writing equal() black magic? Can you give us a short > example of a class that is problematic for equal(const&,const&)? Example of assertion_traits for FileDependency: static bool equal( const FileDependency& x, const FileDependency& y ) { return const_cast<FileDependency&>(x).equalsTo( const_cast<FileDependency *>( &y ) ); } static std::string toString( const FileDependency& x ) { return const_cast<FileDependency&>( x ).toString(); } The const_cast are the things I call "black magic". The code would be much cleaner if: static bool equal( FileDependency& x, FileDependency& y ) { return x.equalsTo( &y ); } static std::string toString( FileDependency& x ) { return x.toString(); } But I just realized, that assertion_traits is not the problem. When specializing a template, you can change the function signature anyway you want. So I could actually write the template the right way (having non-const reference). So that lead us to... (below) > > I'm worried about making the change you propose. I use const a lot, > and I'm sure that I have CppUnit tests in functions that are > passed const references: > > foo( const T& x ) > { > T y(blahblah); > CPPUNIT_ASSERT_EQUAL(x,y); > } > > I think your proposed change would break my code, wouldn't it? Yes, I'm a dummy. I inverted the implicit cast. So the change can't be done the way I proposed (We should add some unit test for the traits I think). How about changing assertEquals() which is the method that actually force the use of const reference ? template <class T> void assertEquals( const T& expected, const T& actual, ... ) => change to : template <class T> void assertEquals( T expected, T actual, ... ) This means that pass-by-value would be use instead of const reference. Means that tested object should either have a copy constructor or be pointer. Baptiste. > > > Thanks, > -Steve --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Steve M. R. <ste...@vi...> - 2001-10-01 19:10:26
|
On Tue, Sep 25, 2001 at 05:13:33PM +0200, Baptiste Lepilleur wrote: > Quoting "Steve M. Robbins" <ste...@vi...>: > > > On Tue, Sep 25, 2001 at 02:56:55PM +0200, Baptiste Lepilleur wrote: > > > > > I'm not saying to change CppUnit as a whole. The only thing I want > > > to change is those part of CppUnit that would impose on the > > > "user" policy: > > > > > > struct assertion_traits > > > { > > > static bool equal( const T& x, const T& y ) > > > => change to > > > static bool equal( T& x, T& y ) > > > > > > and > > > template <class T> > > > void assertEquals( const T& expected, > > > const T& actual, > > > => change to: > > > template <class T> > > > void assertEquals( T& expected, > > > T& actual, > > > > > > The change is invisible for user that apply the "const" policy, and > > allow > > > user who don't to use the assertEquals without having to do > > const_cast. > > > > Sorry Baptiste, I do not understand. Why do you say that using const > > references makes writing equal() black magic? Can you give us a short > > example of a class that is problematic for equal(const&,const&)? > > Example of assertion_traits for FileDependency: > > static bool equal( const FileDependency& x, const FileDependency& y ) > { > return const_cast<FileDependency&>(x).equalsTo( > const_cast<FileDependency *>( &y ) ); > } > > static std::string toString( const FileDependency& x ) > { > return const_cast<FileDependency&>( x ).toString(); > } > > The const_cast are the things I call "black magic". I agree. However, in my mind, this raises the question "why don't the FileDependency methods equalsTo() and toString() have a const qualifier on them?" Yes, I understand: you don't want to impose policy on the user. Fair enough. > template <class T> > void assertEquals( const T& expected, > const T& actual, ... ) > > => change to : > template <class T> > void assertEquals( T expected, > T actual, ... ) > > This means that pass-by-value would be use instead of const reference. > Means that tested object should either have a copy constructor or be pointer. It also implies a lot of useless copying if you're comparing lists, n'est pas? Can't we have both? What about template <class T> void assertEquals( const T& expected, const T& actual, ... ) template <class T> void assertEquals( T& expected, T& actual, ... ) with the same implementation. [Ditto for the default assertion_traits template] I just tried this modification; the library builds and runs the test suite successfully. Comments? -Steve -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Stanley S. <su...@t-...> - 2001-10-01 19:29:33
|
"Steve M. Robbins" wrote: > Can't we have both? What about > > template <class T> > void assertEquals( const T& expected, > const T& actual, ... ) > > template <class T> > void assertEquals( T& expected, > T& actual, ... ) > > with the same implementation. > [Ditto for the default assertion_traits template] > > I just tried this modification; the library builds and runs > the test suite successfully. Comments? > > -Steve > > Cppunit-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppunit-devel This will break on Sun's Forte 6, update 1 compiler, although it is perfectly valid C++, according to both ISO and ANSI. I hope it will be fixed in update 2. -- Stanley M. Sutton sms...@ie... su...@t-... TSurf Corporation - The gOcad Company - http://www.t-surf.com 11011 Richmond Ave. Suite 350 Houston TX 77042 Phone: (1) 713 787 0746 ext. 13 Fax: (1) 713 787 0852 --------------------------------------------------------------------- They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety. - Benjamin Franklin |
From: Duane M. <du...@us...> - 2001-10-01 19:46:03
|
> >Can't we have both? What about > > template <class T> > void assertEquals( const T& expected, > const T& actual, ... ) > > template <class T> > void assertEquals( T& expected, > T& actual, ... ) > >with the same implementation. >[Ditto for the default assertion_traits template] > >I just tried this modification; the library builds and runs >the test suite successfully. Comments? This is perfectly legal C++ (overloads by const). (If Forte doesnt support this, how does it compile the C++ standard library; there are several places where this overload is used.) I would also make the argument (FWIW) that const is all that is needed. Comparison operators should not be mutating. (Caches are caches and should be marked mutable.) This is also where you want to make the change for comparing equivalent objects (not the same type). The change would be thus: template <class TExepect, TActual> void assertEquals( const TExepect & expected, const TActual & actual, ... ) The compiler will complain if the objects cannot be compared. I ran into this problem with my tests. Consider: enum { noErr = 0, someErr = -100 }; int FunctionToTest(); .. CPPUNIT_ASSERT_EQUAL( noErr, FunctionToTest() ); This wont compile because noErr is an anonymous enum type and not an int. The problem with the above change to assertEquals is that it is embedded in a template class that also defines the toString operations on one type. This has to be solved also. A couple of suggestions: (1) seperate the class into two template classes (2) Dont use a template class just template functions (3) Use class template methods (I have the terminology wrong for sure). There may be a limitation with some compilers using this method. Anyhow, just some suggestions. .Duane |
From: Steve M. R. <ste...@vi...> - 2001-10-01 20:32:57
|
On Mon, Oct 01, 2001 at 12:45:40PM -0700, Duane Murphy wrote: > I would also make the argument (FWIW) that const is all that is needed. > Comparison operators should not be mutating. (Caches are caches and > should be marked mutable.) I happen to agree with you. If it were my decision alone, I'd just leave things as-is and let the folks who can't compare const objects to suffer for their sins. ;-) > This is also where you want to make the change for comparing equivalent > objects (not the same type). The change would be thus: > > template <class TExepect, TActual> > void assertEquals( const TExepect & expected, > const TActual & actual, ... ) I'm fairly skeptical that we want to allow this. I seem to recall changing my local copy of CppUnit some months ago to allow assertEquals() on two different types. And I seem to recall running into problems because the compiler likes to promote types and use implicit conversions and all the other good stuff. Sorry to not be more specific at this point... The question, in my mind, is: why are you comparing two different types for equality, anyway??? There are two alternatives that come to mind: 1. Construct an appropriate "expected" value to begin with. If you claim the two types are "equivalent", then you should be able to construct an appropriate object. In the enum/int example, use CPPUNIT_ASSERT_EQUAL( int(noErr), FunctionToTest() ); 2. Make up your own comparison functions and use CPPUNIT_ASSERT. bool my_equality_T1_T2( const T1& x, const T2& y ) { ... } #define CPPUNIT_ASSERT_EQUALS_T1_T2(x,y) \ CPPUNIT_ASSERT( my_equality_T1_T2(x,y) ) I do this sort of thing all the time. Not everything needs to be in the base library. -S -- by Rocket to the Moon, by Airplane to the Rocket, by Taxi to the Airport, by Frontdoor to the Taxi, by throwing back the blanket and laying down the legs ... - They Might Be Giants |
From: Duane M. <dua...@ma...> - 2001-10-01 21:54:39
|
--- At Mon, 1 Oct 2001 16:32:52 -0400, Steve M. Robbins wrote: >On Mon, Oct 01, 2001 at 12:45:40PM -0700, Duane Murphy wrote: > >> I would also make the argument (FWIW) that const is all that is needed. >> Comparison operators should not be mutating. (Caches are caches and >> should be marked mutable.) > >I happen to agree with you. If it were my decision alone, I'd just >leave things as-is and let the folks who can't compare const objects >to suffer for their sins. ;-) In discussing this with our group, we will be removing the non-const features from our version of the library. We feel that it is important to enforce const equality tests. C++ gives us lots of power to do strange and unusual things. We need all the help we can get to make sure we are doing the right thing. >> This is also where you want to make the change for comparing equivalent >> objects (not the same type). The change would be thus: >> >> template <class TExepect, TActual> >> void assertEquals( const TExepect & expected, >> const TActual & actual, ... ) > >I'm fairly skeptical that we want to allow this. > >I seem to recall changing my local copy of CppUnit some months ago to >allow assertEquals() on two different types. And I seem to recall >running into problems because the compiler likes to promote types >and use implicit conversions and all the other good stuff. >Sorry to not be more specific at this point... You are of course correct. This is one of the places that concerns me most in writing C++. Those conversions can magically make code do very unexpected things. >The question, in my mind, is: why are you comparing two different >types for equality, anyway??? > >There are two alternatives that come to mind: > >1. Construct an appropriate "expected" value to begin with. > If you claim the two types are "equivalent", then you should > be able to construct an appropriate object. In the enum/int > example, use CPPUNIT_ASSERT_EQUAL( int(noErr), FunctionToTest() ); This turns out to be the best suggestion for my simple example. >2. Make up your own comparison functions and use CPPUNIT_ASSERT. > > bool my_equality_T1_T2( const T1& x, const T2& y ) { ... } > > #define CPPUNIT_ASSERT_EQUALS_T1_T2(x,y) \ > CPPUNIT_ASSERT( my_equality_T1_T2(x,y) ) > > I do this sort of thing all the time. Not everything needs to be > in the base library. Thanks, this is a good suggestion! |
From: Baptiste L. <gai...@fr...> - 2001-10-02 12:20:28
|
Quoting "Steve M. Robbins" <ste...@vi...>: > On Mon, Oct 01, 2001 at 12:45:40PM -0700, Duane Murphy wrote: > > > I would also make the argument (FWIW) that const is all that is > needed. > > Comparison operators should not be mutating. (Caches are caches and > > should be marked mutable.) > > I happen to agree with you. If it were my decision alone, I'd just > leave things as-is and let the folks who can't compare const objects > to suffer for their sins. ;-) > > > > This is also where you want to make the change for comparing > equivalent > > objects (not the same type). The change would be thus: > > > > template <class TExepect, TActual> > > void assertEquals( const TExepect & expected, > > const TActual & actual, ... ) > > I'm fairly skeptical that we want to allow this. > > I seem to recall changing my local copy of CppUnit some months ago to > allow assertEquals() on two different types. And I seem to recall > running into problems because the compiler likes to promote types > and use implicit conversions and all the other good stuff. > Sorry to not be more specific at this point... Euhh, I don't get it. We can perfectly control implicit conversion by defining one argument constructor explicit. Implicit conversion of basic type is something I (we?) want (unsigned int => int..., const char * => std::string)... It would make the test much easier to read... If unwanted implicit conversion occurs, wouldn't that point out a 'bug' ? Or was the problem, the compiler raising conflict because many conversions were possible ? Baptiste. --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |
From: Baptiste L. <gai...@fr...> - 2001-10-02 12:19:51
|
Quoting Duane Murphy <du...@us...>: > The problem with the above change to assertEquals is that it is > embedded > in a template class that also defines the toString operations on one > type. This has to be solved also. Indeed I'm more bothered with that problem than with the const issue (doesn't raise as often). With VC++, you need to write: std::string str( "123" ); std::vector v; CPPUNIT_ASSERT_EQUAL( 3, int(str.length()) ); CPPUNIT_ASSERT_EQUAL( std::string("123"), str ); CPPUNIT_ASSERT_EQUAL( 0, int(v.size()) ); Which I find make the test much harder to read than: CPPUNIT_ASSERT_EQUAL( 3, str.length() ); CPPUNIT_ASSERT_EQUAL( "123", str ); CPPUNIT_ASSERT_EQUAL( 0, v.size() ); > > A couple of suggestions: > (1) seperate the class into two template classes > (2) Dont use a template class just template functions > (3) Use class template methods (I have the terminology wrong for > sure). > There may be a limitation with some compilers using this method. (3) is to be avoided if we have alternative. VC++ template method support is shacky (TestAssert used to be a class and the assertEquals template method caused Compiler-error). (2) I'm not sure. I think template class are more supported than template function by many compiler. Could any one confirm this ? (1) Separating the equality test from the string conversion is something I'm thinking about. Outputing a message containing an object has must more application than just equality assertion. Thanks to the extra info, we can just deduce what is wrong and we don't have to run the debugger. An object dump often provide a better view of the object than the one you get with the debugger. For example, we might want: CPPUNIT_DETAIL_ASSERT( date.isValid(), date ); which would behave like a standard assertion, but also dump the specified object. Another example, I've a tools utility function that check if 2 unordered collections contains the same elements (they may not be at the same position in the collection): checkCollectionContainsIdenticalItems( expectedCollection, actualCollection, my_equal_predicate() ); When it asserts, it does it with a message listing the expected item that were not in the actual collection, and those that should not be in the actualCollection. That function would use the string dump service but not the 'equality' service (depending of the context, the presence of an item can change: they must have the same 'key', or all their attributes need to be equals...) Well, the point is that the 'dump object to string' service has a much wider range of use than just ASSERT_EQUAL. Baptiste. > > Anyhow, just some suggestions. > > .Duane > > > _______________________________________________ > Cppunit-devel mailing list > Cpp...@li... > https://lists.sourceforge.net/lists/listinfo/cppunit-devel > --- Baptiste Lepilleur <gai...@fr...> http://gaiacrtn.free.fr/index.html Language: English, French |