- A replacement for getters/setters ? - 9 Updates
- Unit testing (Re: Putting project code in many different files) - 4 Updates
- The CRTP -- code reuse and customization? - 5 Updates
- Derivation without size increase? - 1 Update
- The CRTP for interfaces -- not so useful? - 1 Update
- Problematic output of fmod (long double, long double) - 5 Updates
JiiPee <no@notvalid.com>: Feb 11 04:19PM I have always used getters/setters but now I read about them being "evil": http://www.yegor256.com/2014/09/16/getters-and-setters-are-evil.html Lets have an example: class PersonDetails { private: string name; int age; }; Now, how would you get access to name and age without getters and setters? Lets say we have new information about the persons name.... its now "John Smith", was "John". So how to change that name without a setter? |
"K. Frank" <kfrank29.c@gmail.com>: Feb 11 09:15AM -0800 Hi JiiPee! On Thursday, February 11, 2016 at 11:20:11 AM UTC-5, JiiPee wrote: > setters? Lets say we have new information about the persons name.... its > now "John Smith", was "John". > So how to change that name without a setter? I, very frequently, just access the data members directly. Of course, they have to be public to do this: class PersonDetails { public: string name; int age; }; or struct PersonDetails { string name; int age; }; Then just access them: PersonDetails pd; pd.name = "John Smith"; The simpler the class, the less it has class invariants, and the more POD-ish (plain old data) it is, the more likely I am to make data members public, and access them directly. (Stylistically, I often use "struct" instead of "class" for classes that are "morally" POD, as well as for true POD classes.) Having said that, I don't think that getters/setters are evil -- they're just something of a nuisance, especially in simple settings. Best. K. Frank |
Paavo Helde <myfirstname@osa.pri.ee>: Feb 11 08:05PM +0200 On 11.02.2016 18:19, JiiPee wrote: > setters? Lets say we have new information about the persons name.... its > now "John Smith", was "John". > So how to change that name without a setter? If you read a bit past the headline of your link, then you see that he does not advocate removing the setters, but renaming them: person.TakeNewName("John Smith"); person.LiveAndSuffer(Years(30)); Not sure if this is useful for anything. |
scott@slp53.sl.home (Scott Lurndal): Feb 11 06:20PM >setters? Lets say we have new information about the persons name.... its >now "John Smith", was "John". >So how to change that name without a setter? Create a new instance of the object and destroy the original. e.g. have a constructor that takes a reference to the orignal and the updated name. PersonalDetails(PersonalDetails& orig, string newname) { name = newname; age = orig.age; } |
Wouter van Ooijen <wouter@voti.nl>: Feb 11 08:09PM +0100 Op 11-Feb-16 om 5:19 PM schreef JiiPee: > setters? Lets say we have new information about the persons name.... its > now "John Smith", was "John". > So how to change that name without a setter? First, think if it realy makes sense to change the name of the person. Did he/she realy apply for a name change and got permission? And instead of age, why not store the date of birth (which is not likely to change)? Next, pure getters and setters make sense when there is a significant chance that at some moment in the life cycle of your software, you will change the private data without a change in the interface. If you need to do this, you will be very gratefull for the abstraction of the getter/setters. If the chance that you will do that is (almost) zero, getters/setters are a nuisance, and you should instead make the attributes public. Non-pure getters/setters (that do something more than just setting/getting the attribute) are of course a different story. Wouter van Ooijen |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 11 08:41PM +0100 On 2/11/2016 8:09 PM, Wouter van Ooijen wrote: > getter/setters. > If the chance that you will do that is (almost) zero, getters/setters > are a nuisance, and you should instead make the attributes public. Requirements can change. And they do. Bertrand Meyer thought that this was important enough to make member function invocations look like data attribute access in Eiffel, so that a data attribute could be replaced with a member function or vice versa without affecting client source code. He called this the [1]"uniform access principle". I his words, in his 1988 book [2]"Object Oriented Software Construction" (which really was a combined introduction to and rationale of Eiffel, sort of like a combination of Bjarne's TCPPL and Design & Evolution books): "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation". In C++ one can implement uniform access by implementing read only properties, but this has both a memory cost (back-pointer to the object in each such attribute) and an execution cost (extra indirection). I think the uniform access principle is the least weak argument for C++ language support for properties. But ideally, when a direct data attribute is replaced with a read-only property function, that function should be a /pure function/, possibly except caching of results, to avoid the property-with-side-effects nightmare of e.g. properties in C#. And the only guaranteed pure functions in current C++ are `constexpr` functions, which is too restrictive to be useful for this. > Non-pure getters/setters (that do something more than just > setting/getting the attribute) are of course a different story. Yes. Cheers, - Alf Notes: [1] <url: https://en.wikipedia.org/wiki/Uniform_access_principle> [2] <url: https://en.wikipedia.org/wiki/Object-Oriented_Software_Construction> |
Wouter van Ooijen <wouter@voti.nl>: Feb 11 08:51PM +0100 Op 11-Feb-16 om 8:41 PM schreef Alf P. Steinbach: >> If the chance that you will do that is (almost) zero, getters/setters >> are a nuisance, and you should instead make the attributes public. > Requirements can change. That's why my statement doesn'te even mention the (current) requirements. I ask for a judgement call about the future. Getters/setters are a nuisance, but a very small one compared to the updating of a large amount of client code. But there are some cases in which IMO public attributes are the bettre choice, for instance locations (x,y coordinate pairs) on a small (embedded) LCD screen. No chnace in hell that I will ever replace them with an angle/distance pair. But as said, when in doubt favour getters/setters. Wouter van Ooijen |
JiiPee <no@notvalid.com>: Feb 11 07:56PM On 11/02/2016 18:20, Scott Lurndal wrote: > name = newname; > age = orig.age; > } ok, this has a point.... have to think about.... So instead of setter, we would always pass the object and the new value. |
JiiPee <no@notvalid.com>: Feb 11 07:58PM On 11/02/2016 19:09, Wouter van Ooijen wrote: >> So how to change that name without a setter? > If the chance that you will do that is (almost) zero, getters/setters > are a nuisance, and you should instead make the attributes public. Sutter argues strongly that you should always use functions to get access to data members.... |
woodbrian77@gmail.com: Feb 10 03:34PM -0800 On Tuesday, February 9, 2016 at 5:24:28 PM UTC-6, Richard wrote: http://www.wikihow.com/Stop-Swearing Brian Ebenezer Enterprises http://webEbenezer.net |
Ian Collins <ian-news@hotmail.com>: Feb 11 03:10PM +1300 > On Tuesday, February 9, 2016 at 5:24:28 PM UTC-6, Richard wrote: Please stop posting bollocks. -- Ian Collins |
legalize+jeeves@mail.xmission.com (Richard): Feb 11 06:50PM [Please do not mail me a copy of your followup] Ian Collins <ian-news@hotmail.com> spake the secret code >woodbrian77@gmail.com wrote: >> On Tuesday, February 9, 2016 at 5:24:28 PM UTC-6, Richard wrote: >Please stop posting bollocks. I didn't know what you were talking about until I found the shitty post by woodbraindead77. I knew there was a reason I found room for that address in my KILL file. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
Gareth Owen <gwowen@gmail.com>: Feb 11 07:54PM > On Tuesday, February 9, 2016 at 5:24:28 PM UTC-6, Richard wrote: > http://www.wikihow.com/Stop-Swearing http://www.wikihow.com/Stop-Imposing-Your-Bizarre-Moral-Compass-On-Others |
"K. Frank" <kfrank29.c@gmail.com>: Feb 11 09:18AM -0800 I am playing around with the CRTP (curiously recurring template pattern) to get a feel for when it might be useful in practice. Does my simple example below show the full structure of the CRTP, or am I missing an important part of the picture? (As I understand it, you can use the CRTP instead of a similar virtual-function design, avoiding the virtual- function overhead at the cost of giving up run-time polymorphism.) My simple example uses the CRTP for reuse and customization of code. The idea is that Base::doStuff() implements non-trivial logic (trivial in the example) that CRTP-derived classes can reuse and customize by overriding doA(), etc. template<typename D> struct Base { void doStuff() { static_cast<D*>(this)->doA(); static_cast<D*>(this)->doB(); static_cast<D*>(this)->doC(); } // no default for doA void doB() { cout << "Base::doB" << endl; } // default doB void doC() { cout << "Base::doC" << endl; } // default doC }; struct D1 : public Base<D1> { void doA() { cout << "D1::doA" << endl; } // implement doA void doB() { cout << "D1::doB" << endl; } // override doB // use default doC from Base }; Is this the basic structure and purpose of the CRTP? Thanks. K. Frank |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 11 06:56PM +0100 On 2/11/2016 6:18 PM, K. Frank wrote: > // use default doC from Base > }; > Is this the basic structure and purpose of the CRTP? This structure, where a derived class can customize part of a procedure, is called the template pattern. It's one way to use CRTP. In your next posting you describe another way to use CRTP, namely to define a non-virtual interface. The original use of CRTP, by Barton and Nackman in their 1994 book "Scientific and Engineering C++" (if I recall this correctly), was to inherit in a mixin class. E.g. I use CRTP to inherit in relational operators defined in terms of the derived class' `compare` function. This relied on a subtle rule, called "friend name injection", that have since been removed because the Baron-Nackman trick was its only use; instead a friend function defined inline in a class is now found via argument dependent lookup, so that the trick still works. Summing up, the CRTP technique is a basic tool that can be used for many different things. Some people think that using CRTP for compile time polyorphism will always result in code bloat, the compiler generating umpteen slightly different machine code pieces for the same little source snippet. And so it was in early pre-standard C++. But when I measured this around the year 2000 somewhere, for at least some simple small programs the run-time polymorphism yielded less code than using virtual functions. Cheers & hth., - Alf |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Feb 11 07:00PM +0100 On 2/11/2016 6:56 PM, Alf P. Steinbach wrote: > it was in early pre-standard C++. But when I measured this around the > year 2000 somewhere, for at least some simple small programs the > run-time polymorphism yielded less code than using virtual functions. ^^^^^^^^ "compile time" Also, "has" instead of "have" somewhere earlier. Why don't Usenet clients offer a preview, with such errors indicated, when one clicks the "Send" button? Just wondering, - Alf |
Paavo Helde <myfirstname@osa.pri.ee>: Feb 11 08:21PM +0200 On 11.02.2016 20:00, Alf P. Steinbach wrote: > "compile time" > Why don't Usenet clients offer a preview, with such errors indicated, > when one clicks the "Send" button? If the usenet client is smart enough to know what is correct, "compile time" or "run time", then I suspect it won't need your help any more and can answer the posts by itself ;-) |
"K. Frank" <kfrank29.c@gmail.com>: Feb 11 11:39AM -0800 Hi Alf! On Thursday, February 11, 2016 at 12:56:37 PM UTC-5, Alf P. Steinbach wrote: > "Scientific and Engineering C++" (if I recall this correctly), was to > inherit in a mixin class. E.g. I use CRTP to inherit in relational > operators defined in terms of the derived class' `compare` function. I've read through the Barton and Nackman CRTP (as described by Coplien). Would you describe it as fundamentally structurally different than my example, or is it used for a conceptually different purpose, but is structurally the same? I would draw the parallel as follows: operator= (in the CRTP base class) implements the "non-trivial" logic of defining "equals" in terms of "less than." The derived class "customizes" this behavior by implementing operator<. Is there more to the Barton-Nackman machinery than meets my eye? > since been removed because the Barton-Nackman trick was its only use; > instead a friend function defined inline in a class is now found via > argument dependent lookup, so that the trick still works. I assume that "friend name injection" and ADL come into play because we're defining operators (where ADL is most useful), but, other than this syntactic issue, we're just working with otherwise regular member and/or friend functions. Or am I missing something important about the Barton-Nackman structure.? > ... > Cheers & hth., > - Alf Thanks. K. Frank |
red floyd <no.spam@its.invalid>: Feb 11 10:41AM -0800 On 2/10/2016 11:04 AM, Ian Collins wrote: >>> Maybe his concern was the word "crap" - which is not really swearing >> I don't think "crap" is swearing. > So what did you object to? Who gives a shit? |
"K. Frank" <kfrank29.c@gmail.com>: Feb 11 09:28AM -0800 Hello Group! To follow up on my previous post, I have also seen discussions where the CRTP (curiously recurring template pattern) is used, as I understand it, to define interfaces. I suppose that this usage goes something like this: template<typename D> struct Interface { void doA() { static_cast<D*>(this)->implementationA(); } void doB() { static_cast<D*>(this)->implementationB(); } void doC() { static_cast<D*>(this)->implementationC(); } }; Then a class that implements the interface could be: struct D1 : public Interface<D1> { void implementationA() { cout << "D1::implementationA" << endl; } void implementationB() { cout << "D1::implementationB" << endl; } void implementationC() { cout << "D1::implementationC" << endl; } }; and could be used as follows: template<typename T> struct UseInterface { void doStuff() { T t; t.doA(); t.doB(); t.doC(); } }; UseInterface<D1> ud; ud.doStuff; It's true that the class Interface serves to define the interface to be implemented, but having to manually map the interface to the implementation: void doA() { static_cast<D*>(this)->implementationA(); } seems annoying. My preference in a case like this would be to just define a class that "duck-types" the desired interface: struct C { void doA() { cout << "C::doA" << endl; } void doB() { cout << "C::doB" << endl; } void doC() { cout << "C::doC" << endl; } }; and use it, e.g.: UseInterface<C> uc; uc.doStuff; Am I missing anything about the benefits of using the CRTP to define interfaces? If not, do you think that using the CRTP as a place to define an interface is worth the hassle? Thanks. K. Frank |
Alex Vinokur <alex.vinokur@gmail.com>: Feb 11 01:11AM -0800 It seems that output of fmod (long double, long double) in this test is problematocs. Any suggestions? See below. > g++ --version g++ (GCC) 4.9.2 > uname -srvmpio CYGWIN_NT-6.1 1.7.34(0.285/5/3) 2015-02-04 12:12 i686 unknown unknown Cygwin > g++ test1.cpp // No errors, no warnings > ./a.exe l1 = 4294967296 l2 = 72057594037927934 l3 = 4294967294 d1 = 4294967296 d2 = 72057594037927934 d3 = 0 // Expected 4294967294 // -------- Program test1. cpp -------- #include <iostream> #include <iomanip> #include <cmath> int main (int argc, char** argv) { long long l1 = 4294967296; long long l2 = 72057594037927934; long long l3 = l2 % l1; long double d1 = static_cast<long double>(l1); long double d2 = static_cast<long double>(l2); long double d3 = fmod (d2, d1); std::cout << "l1 = " << l1 << std::endl; std::cout << "l2 = " << l2 << std::endl; std::cout << "l3 = " << l3 << std::endl; std::cout << std::endl; std::cout << "d1 = " << std::setprecision(18) << d1 << std::endl; std::cout << "d2 = " << std::setprecision(18) << d2 << std::endl; std::cout << "d3 = " << std::setprecision(18) << d3 << std::endl; return 0; } // ----------------------- |
Paavo Helde <myfirstname@osa.pri.ee>: Feb 11 12:25PM +0200 On 11.02.2016 11:11, Alex Vinokur wrote: > return 0; > } > // ----------------------- The root problem is that d3 gets rounded to a double at some point, becoming 72057594037927936. With MSVC this happens already at d2 definition because in MSVC long double is the same as double. But with gcc it should work in principle as long double has more precision there. Anyway, it seems there are two problems: 1. <cmath> defines fmod() overloads in std:: namespace, so you need to use std::fmod, not fmod. The latter (at least with gcc) only finds the C version fmod(double, double). The std::fmod() works correctly with g++ 4.6.2 on Linux, for example. 2. Even if you use std::fmod(), it seems that Cygwin g++ has not implemented the long double version (it is lacking fmodl() as well), so it is still falling back to the double version. |
jacobnavia <jacob@jacob.remcomp.fr>: Feb 11 11:30AM +0100 CYGWIN uses as its run time the CRTDLL.DLL software of Microsoft. Since Microsoft does NOT implement long double, nothing that uses long double will work under cygwin. The compiler (gcc) does not know this and supposes that long double is different than double. Since printf/fmodl, etc do not work, there are since years always this kinds of questions. Apparently the docs do not tell this very clearly. DO NOT USE LONG DOUBLE WHEN USING CYGWIN! |
Alex Vinokur <alex.vinokur@gmail.com>: Feb 11 02:39AM -0800 On Thursday, February 11, 2016 at 11:12:28 AM UTC+2, Alex Vinokur wrote: |
Alex Vinokur <alex.vinokur@gmail.com>: Feb 11 02:40AM -0800 On Thursday, February 11, 2016 at 12:25:45 PM UTC+2, Paavo Helde wrote: > 2. Even if you use std::fmod(), it seems that Cygwin g++ has not > implemented the long double version (it is lacking fmodl() as well), so > it is still falling back to the double version. Thanks. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment