Why the excessive use of Private classes?!



  • Seriously, whats the reason for classes holding the data instantiated as private, and worse, defined in a .cpp file in almost the entire library? It makes it close to impossible to extent QT, without serious harassment from the library. You tweak the external interface from time to time which requires code changes on our part to upgrade, why not let us have protected access to private data in header files, so we can modify things as we see fit, and upgrade them as necessary. Basically, I'm asking is there a GOOD reason for this, or is it arrogance, narrow mindedness, and/or just plain ignorance? Every single time I try to add some new functionality I run into this trash. I tried copying them to headers, then doing things the QT way, deriving from it, and modifying things that way, to which I was greeted with a message like "Cannot use incompatible QT Versions" when I attempted to run my app with the new found functionality...only way to defeat that was to build the source where I lifted the private class definitions, and only then was all well. Why should I have to do this?! I'm pretty sick of hitting it at every turn...



  • Please be more specific on what you are trying to achieve and you can't do it.

    Because the private data within a class is not stopping you from inherit/compose other classes form that (at least this is how i "extend" the framework, did you tried something different?)

    The private data is the how we achieve encapsulation (OOP principle) and it's recommended for you to create your classes with private data (and code getter and setter member functions for that)



  • The Private classes are used for the sakes of ensuring binary compatibility between different versions of Qt.

    See [1] and [2] for more info

    [1] "wikipedia.org :: D-pointer":http://en.wikipedia.org/wiki/D-pointer
    [2] "techbase.kde.org :: D-Pointers":http://techbase.kde.org/Policies/Library_Code_Policy#D-Pointers



  • I really am trying to be brief, and not too standoffish about this, because I really do know what I'm doing, and have been burned by private data in the past, just like 100000's of other programmers out there googling getting access to private data...

    First off, I can't go into too much detail about what we're doing. Second, As I have been typing, I'm remembering more from my trauma with this. The files were in fact, in header files, usually classname_p.h, so yeah, I goofed on that one, I just couldn't gigure out why Qt would complain at what I'm doing.

    The first issue came up when I decided I wanted a 64 bit QAbstractScrollArea. We do lots with 64 bit stuff here, and having a 64 bit scroll area would simplify life a lot, and make the code more maintainable, so I did what you just reccomended. To accomplish this, I had to copy in 10 classname_p.h files, all the way down to qwidget_p.h. To get these, I went to archive.ubuntu.com, and got the orig.tar.gz. The patch looked like it was just a bunch of debian script stuff, so I figured there were no code changes, I should just be able to copy the _p.h files out. When I did that, made my derived classes, used my 64bit scroll area, everything compiled just fine. I went to run it, and got the aforementioned incompatible Qt Library message. It was in fact, 4.6.2, the same version Ubuntu (and fedora) had claimed to install. Both machines did the same thing. When I recompiled Qt, from the 4.6.2 orig tar.gz from archive.ubuntu.com though, everything was OK. I checked and rechecked the versions, everything matched. Somehow, Qt knows I lifted the files, and not from the .deb or .rpm installs (since they don't install those files) So now, whenever I want to extend Qt, I have to provide a stock, but custom built version to make it work.

    If there is some secret sauce feed to Qt to have it allow me to extend this private data without the Incompatible Qt Versions, I'd love to know...things would be so much easier. As it is, I'm rewriting QThread now because of this behavior...not exactly happy about it either (though I only recently started using QThread as opposed to writing it myself, but I had made the switch and find myself now disappointed)



  • Ivan: Still doesn't explain the use of private over protected. After decades of coding, I'm throughly convinced that one should NEVER use private unless one has a VERY good reason for doing so. It causes more problems, headaches, etc than its worth when someone decides you were narrow minded, and never accounted for z functionality that may be wanted along with x and y you implemented....now the programmer has to go back reimplement x and y, along with z, all because you decided to use private instead of protected....



  • The "incompatible Qt Library message" is shown when you try to run a program with a different/modified version of Qt compared to the one that is already loaded by some other program (Trolls would probably be able to tell the exact reason)

    "Still doesn’t explain the use of private over protected"

    It really does. As a library, it is not meant to the allow users to rely on the implementation itself, but only on the behaviour. It is the clean OOP. Exposing the implementation in any way means that you can't ever change (that part) of the implementation w/o breaking the back-compatibility which would mean the library is still-born.

    I know the feeling when you want to use something private, but can't, but regarding to the above, it is a necessity.

    If you want custom Qt classes, I'd always suggest copying the originals and changing rather than changing/forking Qt itself.



  • "should NEVER use private unless one has a VERY good reason"

    From a library-devel point of view, this rule looks like this:

    "should NEVER use non-private unless one has a VERY good reason"

    :)



  • The incompatible qt message came up without modification, so unless I totally missed something in the patch file, and Qt recognized that from the inclusion of a few _p.h files, you're wrong about that being the only way that message appears. I assure you I made no changes to the library source code at all, and only included a few _p headers, I'd not be here asking about these problems were that not the case.

    As for the implementation, you can change it, it just means your clientel doesn't get to be lazy when it comes time to upgrade. Further, there are better ways of doing things. Heck, if they would just provide accessors to be basic of the basics in these classes, it wouldn't be a problem, but instead they happily move along why would anyone need this? Nope, no accessor, meanwhile I'm out here saying Hello? Thats a pretty basic member, and yes, I do need it. Its short sighted. If you're going to be short sighted, at least use protected members so we don't all suffer for it.

    Further, library code is no exception for the rule I stated, in fact, its where its most important. Inside your application, its not a big deal to recompile and change things, and you shouldn't be exporting functions from an executable. Granted in...some...situations, its very difficult even within the same executable, or even component of a system to change the code because of CM boards, and whatnot, but libraries you're almost guaranteed to run into this issue. The only way to resolve it is either you are god, and forsee all possible uses of your code, or you don't overprotect. If Joe Coder off the street decides he wants to add functionality to your system he simply links to you library, derives a new class, access the protected members for the custom functionality he wants, without ever breaking anything. If he does, what did he break it for, thats right, ONLY, his own program, not the library, not other things linked to the library, his own program.

    Your thinking it is a necessity is where thinking like Coolant must flow into the engine block of an engine first rather than the heads came from, when GM switched it with the LT1 design, they saw huge performance gains. Similarly, at Microsoft, everyone said when cloning a machine, you must change the SID, till one day they all sat around and said, well, what would happen if you don't. Everyone assumed someone else had the answer, there was in fact, no security vulnerability, network problems or otherwise, and the changesid project was abandoned. You've been fed by your OOP teachers you must make everything private. Give it a few years in industry, and start asking yourself, whats the worse thing that would happen if this were protected? Oh, some user might break his own application and effect himself, and learn his lesson pretty quickly.

    I'm also not going to get into how QT isn't exactly OOP, but to be arguing it follows good OOP design concepts is like saying selling ice to eskimo's is a good business strategy. I love Qt, but I do understand its...less desirable...aspects. Just like any healty loving relationship though, there are always things you dislike about the other. :)

    Lastly, branching? That pretty much defeats the purpose of having a distribution. I realize Trolltech didn't make the ubuntu, fedora, centos, etc packages, but they are there none-the-less. Its pretty poor form to require another version, especially for something trivial...and there are cases where licensing doesn't allow for such.



  • Look, if libraries were made your way, instead of having a download page for your application with choices for the OS, you'd have to have different executables for different versions, subversions... of Qt.

    I really don't like repeating myself, especially so when someone is trying to be condescending.

    Cheerio



  • Look, I'm not trying to be condescending, but you are in fact, accepting everything without your own thought. Do you really think threadId in QThread is going to change much from 4.3.2 to 4.6.2, how about scroll position. There are so many very basic items that need not worry about changing, that they need not squirrel away in opaque types, thus the use of excessive in the title. Its like taking an OOP concept to an extreme. Technically speaking, making quint32 a class is good OOP design, but is it necessary, does it make life difficult for devs, should it be done? Putting literally (not figuratively) everything in private opaque types is the equivilant in OOP excessive. Thats all I'm going to say on the opaque types.

    As for permissions, you know that 90% of programs out there are pretty basic gui apps, doing pretty basic things. Allowing 10% of them access to those things private isn't going to cause mass panic as you describe. 10% of the applications may be tied to a particular library version, and its the responsibility of those devs to upgrade it. However, its not like concurrent library versions can't exist on the same machine. To say its going to cause nothing to work anymore, a form of mass panic in the software world, is more of a hyperbole than anything I have said, only you seem absolutly serious about it.

    Another example, this is like how there are 2 schools of though in the IT world, let the users manage themselves, and punish the lusers and don't give them any privileges lest they break something. Time and time again, the admins who allow the users who know what they are doing to do it, they have less work for themselves, sometimes have trouble users, but, thats how its going to be. The admin who lets no one do anything constantly finds himself barraged with calls to allow a program to be installed, or a folder to be created, and thus, sure nothing breaks, but he has more work for himself. Why then are we going to innundate trolltech with change requests for I need a getter, for value x. Why not just allow most common, stable items, and block only those things still in flux? You know, make it private only if there is a good reason for it?

    I asked a few other devs I work with, and some I have still kept in contact with since college. We all work professionally, and have for some time, and all agree, protected is the way to go...its those who have never had to live with the consequences of that decision who still rally for it...Thats why I'm not surprised to see a library vendor still rallying around it, and of source when they hit a snag, they just change their own source, thus, never live with the conseqences of their decisions.

    Let those of us with our 10% of applications do what we need to, and maintain our versions. If it turns out the functionality is as cool as we think it is, then we'll see about filing a change request and getting it into the main library interface. Making us have to rebuild the library for not a single change to the library source though, to access these private opaque types is just plain insane. At the very very least, I should be able to include the _p.h files, derive classes, and have things work without the incompatible qt library message coming up. I honestly really shouldn't have to go grab the source, find the _p.h file I need, find all the other _p.h files it includes, and that they include, only to come up with that obnoxious error message. I wasted 2 days on making a 64 bit scroll area, it should have taken 2 hours, and making it take 2 hours would not have harmed the software repositories, or the software contained therein, at all.

    I really feel I have proven repeatedly now this is the case. I have been writing code since I was 8 years old, never liked the idea of private, and never used it except where it really was necessary. Since then I have worked as a professional dev, and had collegues thank me for my wider vision. Funny how it didn't break anything then, and will continue not to break things. It comes with an inherent risk, and I make that clear, but I don't need to babysit other devs, and I most certainly don't need you, or Trolltech to babysit me. I'm a big boy now, I know when I access a protected member, things might change on me, and I deal with it.



  • With all due respect to your age and everything (although you were a bit late starter), but if you can say that "Allowing 10% of them access to those things private isn’t going to cause mass panic as you describe" then you have no idea how C++ libraries work.

    I suggest diving a bit more into inner workings of C and C++ before making statements like these.

    As for "Look, I’m not trying to be condescending, but you are in fact, accepting everything without your own thought", I can only laugh and say that even if it were true, people I've been privileged to work with (and to learn from) in the last decade of my life are not held in high regards only by their colegues...



  • I do know how C++ libraries work. I also know how C libraries work. I also know the differences between windows and linux libraries, and the challenges of porting between the 2. I've worked pretty extensivly with all permutations of the above. I have worked with some of the most underrecognized (because of the field I happen to be in) brightest people you could imagine. We all fed off one another, and made some really disruptive stuff, in a short amount of time. I've worked with brilliant outside vendors for products, some who maintained their own libraries, some we maintained their libraries for them. Dont think for a second I don't have a lot of experience with what I'm talking about. Either you aren't getting what parts it is I am saying need change, you don't have the same understanding, or you're just accepting what someone else told you. I'm not really sure which it is. Reguardless, I have maintained binary compatibility in other more flexible means, I have never once had a problem with making things protetected that didnt need to be protected from a derived class. I can think of some...very popular, commercial...systems...that do just this, and feel no need to deny access. Goes right back to the sysadmin example...

    That said, because of the overprotection, and simplicity of the QThread class, I now have a fully functional replacement, with more functionality than QThread, including read access to the thread ID (not handle/pthread_t object, the 32 bit id in windows, and linux. Dont much care for OSX for the stuff I write). Funny how overprotection leads to uselessness, and eventual replacement with something not overprotected. It shouldn't be this way, and many highly successful commercial ventures understand this principal very well.



  • This has to be the funniest rant I have ever read....



  • If you're referring to my (to me anyways) hilarious hyperbole similes, then I'm glad you got the humor :) I try to make things funny all the time, and laugh at everything, including myself. If you think I'm an idiot, well, too bad, if you think Ivan's an idiot, again too bad. If you think the whole argument is funny, well, I suppose I can laugh at it too, but I am serious in that overprotection is as bad as underprotection :)



  • "overprotection is as bad as underprotection"

    ok, on this we agree, we just have the different barrier and definitions of over/underprotection :)



  • Let's just poke about in this discussion some more. Have a look at Meyer's "Uniform Access Principle":http://en.wikipedia.org/wiki/Uniform_access_principle . It states that

    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.

    This is in my view a heavy endorsement of privately held data, while accessors are protected or public. This means you can dump everything into a pimpled class's private parts, while still having access to all information. More so, it gives you every freedom of changing the way the function works without having to force a recompilation of your entire program. Instead you only have to compile 1 source file and link the entire thing again.

    Aside from that, having member variables directly accessible from the outside increases coupling of your classes. Your class is responsible for the state it is in, not the outside world.



  • Ok, first off, let me tackle what was said there, and what you said. Uniform notation, which does not betray...where do you get private from that? Thats saying to design a proper interface, and stick to it. What that is saying is hide how the data is generated, not hide the data. Read it again. The data can be private, protected, or public, and still have how the data is generated hidden. All it is saying is to have a function to access each element of the data that is accessible. I generally don't agree 100% with that, but I see the value in a lot of cases. However, if you are going to go that route, you really need to provide a FULL interface, not a partial one, which is my complaint with Qt. (Actually, I can't even really call it an interface since there would be, well, an interface, and an implementation, not a need to include a private data header...thus the reason I didn't immedatly recognize it as such).

    Yeah, I can get access to the data I need for 90% of what I want to do. Accessors like text() and setText(). Fine, I guess its obvious I might want to do something with the text of widgets....but I don't know, I thought it would be obvious that I might want to have OS provided unique thread ids accessible for reading, but as it turns out, according to Trolltech, I'd be wrong. Clearly threads are supposed to be in their own little world doing their own little task. Only, I'm not. A properly designed interface would give me access to all the data members through accessors, because it would have been necessary for the implementation of the interface.

    Basically the problem is like I said in a previous post they aren't forced to live with the consequences of their decisions, only I'll rephrase it slightly, by not going with a full interface seperation, they aren't being forced to live with the consequences of their decisions. When you seperate out the interface, you find you need accessors for everything, and you don't clutter things up with private headers with comments about how this will change, we mean it. Instead, they have to use, protected accessors for everything, because you have to derive from the interface to implement it. Thus, you live with the consequences of your interface design, and make sure you get it pretty well rounded before it ever hits release.

    If you have ever worked with a library done in with full interface/implementation seperation, you know, theres nothing thats difficult to extend, oh, and it doesn't break binary compatibility. IMO, this hybrid approach is the lazy way out, and renders some classes, or rather pseudo-interfaces useless.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.