> However, it seems like users are building up a > trust relationship with the computer they've used > sucessfully before
Of course they are. It takes an enormous amount of effort to get a computer behaving just the way you want it to (especially if it is running Linux), and more effort to keep it that way (especially if it is running Windows).
> It's almost as if users are presuming that most > unfamiliar computers will fail on them
But they do! How much are you willing to entrust to a computer run by a man heard to utter "I don't care how the damn thing works; just set it up for me to print my memos!"?
> stepping out of that car in your brand spanking > new spandex Tron suite. The girls would be over > you like bees on honey...!
Unfortunately, if you look closely, you'll see that the girls are all dressed in white and are carrying syringes. You probably won't have much time to conteplate it.
> how many Libraries Of Congress (LOCs) can I fit on > a disk the size of a credit card?
What I want to know is why we still can't get the Library of Congress on any electronic medium at all. I want my two thousand DVDs now! I am sure a pony would be able to handle them...
> I still get the impression that you're of the "once good, always good" school
I am and here is why: "once good, always good" is the property of good design. In fact, it is probably one of the most important indicators of good design. If you encapsulate your code into components with well defined interfaces, there will be no way for a change to your component to break other components. When you see a break that means one of three things: 1. the application is too monolithic, with components reaching greedy tentacles into what does not belong to them, 2. you changed the component's interface and did not tell your users, 3. the component's interface is either not well defined or it is too complex. In the first case, refactoring is the solution. Separate and simplify; but you already know that. The second case is quite common, and is solved by better communication with the users of your component. When you make a release, note the changes that require code modification; most OSS libraries do this in one way or another. The third case happens when you make kitchen sink components that have no single function. It is simple to verify that function if it is something like "take this data and compress it", but quite difficult when you have an MFC CView derivative which contains the entire visualization code for your 3D CAD. I tend to have extremely simple functions for each component, usually just "convert format A into B" from the bottom all the way to the UI drawlist, so I almost never have any bugs due to a broken algorithm. When I have problems it is always when something doesn't fit into the design. I can not write an automated test to detect such a problem because if I could predict the it, I wouldn't have it. Which brings me to another point:
> The last thing you want is your intern looking > at the output - he can make a mistake. Your > xUnit test cases can't.
If he makes a mistake looking at the output then his code will not work, meaning that it will not properly accomplish its function, meaning that the erroneous result will be obvious in the UI. For example, if he is writing settings into the registry and has to change a number, that number will either be set correctly or it will not be. In a good design his changes will only affect the very narrow functionality that he is working on, namely the sequence of calls to your registry access layer. It would not be possible to affect anything else, so it will still all work.
> how do you plan to validate that the code works?
By knowing how it is supposed to work and documenting the boundaries with asserts. Then your randomly poking intern will not be able to complete even a single test run if he screws up (you do require at least basic testing and code review for every checking, don't you?). For example, say you are writing a preprocessor. I had to write one once to substitute variables into a LDAP import file for a setup program. This code was used by a bunch of people, the input being the filename, output buffer (resizable), and the map of variables to substitute. How did I know it worked? By carefully designing the algorithm. I made sure that it correctly resized the buffer for the output when it ran out of room, that there were exception handlers for things like missing files, that substitution worked correctly for all three cases (long->short, short->long, equal length). And then I stepped through the code for all three cases. (You do step through all your new code at least once, right? Or at least somehow make sure that it actually ran?) Then I put in precondition asserts, like an empty filename (this must be checked in the UI by graying out the button), or empty source substitution strings (which were hardcoded in some header file). The output buffer was dynamically resized, so there was nothing to screw up in that parameter. The STL map ensured that there would always be valid objects to substitute. And, if the poor intern passed in something he should not have, well, I can't check for that since I can't know what he intended. He'll have to actually (*gasp*) look at the output.
> assertions in the code and have an intern poke at the GUI randomly?
Hell no. He'll have to test his new code, just like I did. Otherwise, no checkin. And don't let interns mess with core components either. They should only work with leaf code and delegate when they find a bug in the core.
> Imagine if you've got 200 people working on a project.
Don't have 200 people working on a project. Have 19 groups of 10 people working on 19 separate standalone projects which can be combined by the 20th standalone project. Use the unix philosophy. It really works. Simplify, simplify, simplify. Define interfaces between those projects and ensure they are not broken. Write some assertions and NDEBUG code to verify that the data your component gets is valid and then you'll know your code will work because you have written it, you have stepped through it, and you know how it works and why.
> it is all too easy to use MI incorrectly and screw things up with improper casting.
If you use casting, the problem is not with MI, but with your understanding of inheritance. In a good design you never have to cast anything. The only difficulty in understanding MI casting is that you have to realize that you can't cast to another branch. This is because the branches are not derived from each other and just because you have one class that merges both branches, does not mean that there no other such merges. Until you understand this, you should not be using MI. Just as you should not be driving until you know which side of the road to use.
> it is a particularly difficult feature for compiler writers to implement.
Not really. It will be difficult for you if only if you wrote your compiler with single inheritance only and hardcoded all your poor assumptions. There will be some tedious code for checking virtual bases and merging of vtables, but it should all be fairly straightforward. The output is simply a vtable pointer for each branch and you need to make sure you know which function call uses which vtable.
> when there are other language constructs that can do just as good
Like what? I can't think of any simpler way to implement this functionality. I mean, what can be simpler than two vtables? It's what you would do if you aggregated the interfaces through member variables too.
I just looked at two unit test suites I could find, namely jUnit and cxxunit, and I have to say that I was wrong to say that the debugger is the unit testing support for C++. In reality, assert() is the unit testing support for C++ (and C, of course). The unit testing frameworks appear to be nothing but collections of assert functions combined with a graphical tool to catch them. Of course, every self-respecting programmer has asserts in his code. Advanced programmers often have more asserts than real code, and write error diagnostic routines which "explain" more generic exceptions or dump out relevant data structures. Really advanced programmers write their comments in asserts (Incidentally, do you know this trick: assert(!p && "You must allocate a buffer before passing in the fragment");?) As for the GUI, we have the shell, which prints out the assertion messages quite nicely. C++ assertions are also always fatal, which is a very good thing because it forces you to fix things, unlike the unit test framework's GUI, where failures are ignorable.
> You might catch an exception and but not have the faintest idea who threw it.
That's correct. It does not matter one bit who threw the exception; the only things that matter are one: there was an exception, and two: the problem that caused it. The exception should name the problem, not the thrower. You do not have to handle every exception, and neither should you try to. All you should do is clean up and report the error (which you can easily do if you design your exceptions with an appropriate interface). If you don't need to cleanup, which would be true for almost all functions, you don't need try/catch blocks either. And don't blame exceptions for the bad design of COM interfaces either.
> Unit testing and debugging are the same thing to you?
Not exactly. I think unit testing (as in having a bunch of little programs that go through each code path) is useful to some degree, but is not a solution to all your problems. If your interfaces are clean and you know what your objects are doing, unit testing is probably superfluous. Mostly it means you spend more time writing tests than fixing your code, and the latter is what I would rather be doing. You might object that there are bugs that I could miss this way, and you are correct; however it is unlikely. Most of my code is very simple in implementation; complexity arises from combination of simple components in logical fashion, so my bugs are usually of the kind that tells me there is something wrong with my design. This is not something you can write a test for, but it is usually obvious when something does not fit.
> a high incidence of memory management related > problems, which are often very hard to find
If you use STL or some other MM encapsulation classes, you will have NO memory management related problems. Ever. This is quite unlike C code, where you really do have to remember to free the mallocs. In C++ you never allocate any memory at all. Only newbies do it before they either learn STL or write their own.
> common security issues, often involving buffer overflows
Buffer overflows are not solved by making another programming language. They are solved by fixing your algorithms. They are solved by ditching hand coded text parsers or, better yet, ditching text files of all kinds altogether. Use a packaged XML library to parse your input (you do have all your config files in XML, don't you?) and use libreadline or something for the shell. If you keep reinventing the wheel, don't whine about it breaking.
> compiler incompatibilities, including frequent > lack of proper template support, exception > handling, namespaces
That's why you use gcc for everything. gcc supports all those things you mention and is available on every platform worth mentioning. Don't blame the language when your vendor insists on locking you into their lousy compiler.
> obscure and often terribly non-intuitive syntax
Bullshit. C++ makes for a beautiful syntax. You just have no taste!;) Seriously, a good C++ programmer can create interfaces that would make you drool. And as for newbies, well, they can write ugly code in any language.
> overly complex and redundant idioms necessary to > work around language shortcomings
C++ has no shortcomings. What are you talking about?:) As for idioms, all the other languages have them too.
> they just switch to a more productive > language...like the majority of the software > industry is doing.
No they are not. The majority of the software industry are concerned with developing web applications. You can't do that in C++ because you do not want the stupid user to install anything but a browser. C++ is for real applications that run on your machine, like an application is supposed to.
While you are waiting, try this instead:
on
Nanotech or Nano-Not?
·
· Score: 2, Insightful
Every once in a while people try to improve on C++. Usually it is those wet-behind-the-ears kids straight out of college who think that because C++ is too hard for them, it is a bad language. But real programmers just shrug and keep on coding in C++. Let the kids have their fun; they'll come around eventually when they want to write some real code. Maybe someday they'll discover that garbage collection is not necessary when you know who owns your memory and encapsulate allocation in logical places, like STL containers. They'll discover that C++ already has overridable operators, full (well, all that matters, anyhow) C compatibility, native compilation (VMs are for script kiddies), inline assembler, and in-built support for unit testing (called a debugger). And as for "Design by Contract", good luck getting any contracts in your new D.
> a=1, b=4, c=6, d=3, e=7 > what is ((a*b)+(c-a))-((d/f)+(c-a))
You don't need to refer back to the values at all. Just think of them as a vector f in function space G: (1,4,6,3,7). Then imagine an isomorphic mapping between integers 1 through 5 and the first five letters of the alphabet. The evaluation of any simple polynomial, such as the one presented above, is now trivial and is left as an exercise for the reader.
I wrote in the URL as a joke, but I figured I might as well see if it exists. Believe it or not, it does. And from the front page (the FRONT PAGE) you can really find brain pills!!! So, should I laugh, scream, or cry?
Do you sometimes feel inadequate? Do you seem to forget important things? Would you like to be smarter, more educated, and get laid every day? Get our brain cache enlargement pills today! They are a wholly natural way of increasing your brain's "cache", or the very short term memory. Our pills contain no harmful chemicals, in fact, they contain no chemicals at all! Everything in them is completely natural and wholesome. Visit our website at http://www.brainpills.com for many wonderful success stories from our customers. Our pills work, so get yours today!
> Like, dude. That's what the propeller beanie is for.
Make sure you get the correct model of the propeller beanie. The kind with a motor inside. There are plenty of cheap imitations whose propeller only spins by convection. Such deplorable designs actually increase heat retention by obstructing upward heat flow. Of course, nothing beats water cooling for reducing heat in the head. A bucket of cold water is a low-tech, but effective method of obtaining positive results.
The discoveries said there _was_ water on mars, not that there is any now. It might still be there somewhere, but not in any quantity that can rust a gram of steel.
> My point is, that we re-create the same dwelling/software over and over again.
Pehaps you are just oscillating around an optimal point.
> As for the energy efficiency, um, I'd have to call > bullshit there. Part of a energy efficent dwelling > has to do with the balance of breathability to airtightness.
Breathability has nothing to do with energy efficiency (although it is still worth considering if you want to keep breathing:). Earthworks are energy efficient because their large mass stores the heat as it leaves the living area. When heat leaves your house walls, it is gone into the air; when the heat goes into an earth wall, it creates a gradient which reduces further heat loss. In deserts, where night is very cold and day is very hot, the walls will actually feed back the heat stored during the day into the living area at night, drastically reducing your temperature swings.
> Mudhuts are not all that well sealed.
I am not talking about mud-and-wattle huts, which are about as energy efficient as a cardboard box, and less comfortable. I am talking about massive earth structures with three foot thick walls. See earthship.org, for an example.
> However, it seems like users are building up a
> trust relationship with the computer they've used
> sucessfully before
Of course they are. It takes an enormous amount of effort to get a computer behaving just the way you want it to (especially if it is running Linux), and more effort to keep it that way (especially if it is running Windows).
> It's almost as if users are presuming that most
> unfamiliar computers will fail on them
But they do! How much are you willing to entrust to a computer run by a man heard to utter "I don't care how the damn thing works; just set it up for me to print my memos!"?
> my friend's father has a PhD from Oxford, and now drives a bus
:)
> He's far happier than he used to be.
So, John Galt was right
> terraforming Mars & Venus... Anyone want to buy some cheap land??
Sure. As soon as you can have it surveyed and marked by a licensed professional.
> stepping out of that car in your brand spanking
> new spandex Tron suite. The girls would be over
> you like bees on honey...!
Unfortunately, if you look closely, you'll see that the girls are all dressed in white and are carrying syringes. You probably won't have much time to conteplate it.
> how many Libraries Of Congress (LOCs) can I fit on
> a disk the size of a credit card?
What I want to know is why we still can't get the Library of Congress on any electronic medium at all. I want my two thousand DVDs now! I am sure a pony would be able to handle them...
> I still get the impression that you're of the "once good, always good" school
I am and here is why: "once good, always good" is the property of good design. In fact, it is probably one of the most important indicators of good design. If you encapsulate your code into components with well defined interfaces, there will be no way for a change to your component to break other components. When you see a break that means one of three things: 1. the application is too monolithic, with components reaching greedy tentacles into what does not belong to them, 2. you changed the component's interface and did not tell your users, 3. the component's interface is either not well defined or it is too complex. In the first case, refactoring is the solution. Separate and simplify; but you already know that. The second case is quite common, and is solved by better communication with the users of your component. When you make a release, note the changes that require code modification; most OSS libraries do this in one way or another. The third case happens when you make kitchen sink components that have no single function. It is simple to verify that function if it is something like "take this data and compress it", but quite difficult when you have an MFC CView derivative which contains the entire visualization code for your 3D CAD. I tend to have extremely simple functions for each component, usually just "convert format A into B" from the bottom all the way to the UI drawlist, so I almost never have any bugs due to a broken algorithm. When I have problems it is always when something doesn't fit into the design. I can not write an automated test to detect such a problem because if I could predict the it, I wouldn't have it. Which brings me to another point:
> The last thing you want is your intern looking
> at the output - he can make a mistake. Your
> xUnit test cases can't.
If he makes a mistake looking at the output then his code will not work, meaning that it will not properly accomplish its function, meaning that the erroneous result will be obvious in the UI. For example, if he is writing settings into the registry and has to change a number, that number will either be set correctly or it will not be. In a good design his changes will only affect the very narrow functionality that he is working on, namely the sequence of calls to your registry access layer. It would not be possible to affect anything else, so it will still all work.
> how do you plan to validate that the code works?
By knowing how it is supposed to work and documenting the boundaries with asserts. Then your randomly poking intern will not be able to complete even a single test run if he screws up (you do require at least basic testing and code review for every checking, don't you?). For example, say you are writing a preprocessor. I had to write one once to substitute variables into a LDAP import file for a setup program. This code was used by a bunch of people, the input being the filename, output buffer (resizable), and the map of variables to substitute. How did I know it worked? By carefully designing the algorithm. I made sure that it correctly resized the buffer for the output when it ran out of room, that there were exception handlers for things like missing files, that substitution worked correctly for all three cases (long->short, short->long, equal length). And then I stepped through the code for all three cases. (You do step through all your new code at least once, right? Or at least somehow make sure that it actually ran?) Then I put in precondition asserts, like an empty filename (this must be checked in the UI by graying out the button), or empty source substitution strings (which were hardcoded in some header file). The output buffer was dynamically resized, so there was nothing to screw up in that parameter. The STL map ensured that there would always be valid objects to substitute. And, if the poor intern passed in something he should not have, well, I can't check for that since I can't know what he intended. He'll have to actually (*gasp*) look at the output.
> assertions in the code and have an intern poke at the GUI randomly?
Hell no. He'll have to test his new code, just like I did. Otherwise, no checkin. And don't let interns mess with core components either. They should only work with leaf code and delegate when they find a bug in the core.
> Imagine if you've got 200 people working on a project.
Don't have 200 people working on a project. Have 19 groups of 10 people working on 19 separate standalone projects which can be combined by the 20th standalone project. Use the unix philosophy. It really works. Simplify, simplify, simplify. Define interfaces between those projects and ensure they are not broken. Write some assertions and NDEBUG code to verify that the data your component gets is valid and then you'll know your code will work because you have written it, you have stepped through it, and you know how it works and why.
> it is all too easy to use MI incorrectly and screw things up with improper casting.
If you use casting, the problem is not with MI, but with your understanding of inheritance. In a good design you never have to cast anything. The only difficulty in understanding MI casting is that you have to realize that you can't cast to another branch. This is because the branches are not derived from each other and just because you have one class that merges both branches, does not mean that there no other such merges. Until you understand this, you should not be using MI. Just as you should not be driving until you know which side of the road to use.
> it is a particularly difficult feature for compiler writers to implement.
Not really. It will be difficult for you if only if you wrote your compiler with single inheritance only and hardcoded all your poor assumptions. There will be some tedious code for checking virtual bases and merging of vtables, but it should all be fairly straightforward. The output is simply a vtable pointer for each branch and you need to make sure you know which function call uses which vtable.
> when there are other language constructs that can do just as good
Like what? I can't think of any simpler way to implement this functionality. I mean, what can be simpler than two vtables? It's what you would do if you aggregated the interfaces through member variables too.
I just looked at two unit test suites I could find, namely jUnit and cxxunit, and I have to say that I was wrong to say that the debugger is the unit testing support for C++. In reality, assert() is the unit testing support for C++ (and C, of course). The unit testing frameworks appear to be nothing but collections of assert functions combined with a graphical tool to catch them. Of course, every self-respecting programmer has asserts in his code. Advanced programmers often have more asserts than real code, and write error diagnostic routines which "explain" more generic exceptions or dump out relevant data structures. Really advanced programmers write their comments in asserts (Incidentally, do you know this trick: assert(!p && "You must allocate a buffer before passing in the fragment");?) As for the GUI, we have the shell, which prints out the assertion messages quite nicely. C++ assertions are also always fatal, which is a very good thing because it forces you to fix things, unlike the unit test framework's GUI, where failures are ignorable.
> I don't think you understand the disadvantages of multiple inheritance.
You are entirely correct. I do not. Perhaps you would like to enlighten me? I have many classes using MI and I find the result very clean and simple.
> You might catch an exception and but not have the faintest idea who threw it.
That's correct. It does not matter one bit who threw the exception; the only things that matter are one: there was an exception, and two: the problem that caused it. The exception should name the problem, not the thrower. You do not have to handle every exception, and neither should you try to. All you should do is clean up and report the error (which you can easily do if you design your exceptions with an appropriate interface). If you don't need to cleanup, which would be true for almost all functions, you don't need try/catch blocks either. And don't blame exceptions for the bad design of COM interfaces either.
> Unit testing and debugging are the same thing to you?
Not exactly. I think unit testing (as in having a bunch of little programs that go through each code path) is useful to some degree, but is not a solution to all your problems. If your interfaces are clean and you know what your objects are doing, unit testing is probably superfluous. Mostly it means you spend more time writing tests than fixing your code, and the latter is what I would rather be doing. You might object that there are bugs that I could miss this way, and you are correct; however it is unlikely. Most of my code is very simple in implementation; complexity arises from combination of simple components in logical fashion, so my bugs are usually of the kind that tells me there is something wrong with my design. This is not something you can write a test for, but it is usually obvious when something does not fit.
> a high incidence of memory management related
;) Seriously, a good C++ programmer can create interfaces that would make you drool. And as for newbies, well, they can write ugly code in any language.
:) As for idioms, all the other languages have them too.
> problems, which are often very hard to find
If you use STL or some other MM encapsulation classes, you will have NO memory management related problems. Ever. This is quite unlike C code, where you really do have to remember to free the mallocs. In C++ you never allocate any memory at all. Only newbies do it before they either learn STL or write their own.
> common security issues, often involving buffer overflows
Buffer overflows are not solved by making another programming language. They are solved by fixing your algorithms. They are solved by ditching hand coded text parsers or, better yet, ditching text files of all kinds altogether. Use a packaged XML library to parse your input (you do have all your config files in XML, don't you?) and use libreadline or something for the shell. If you keep reinventing the wheel, don't whine about it breaking.
> compiler incompatibilities, including frequent
> lack of proper template support, exception
> handling, namespaces
That's why you use gcc for everything. gcc supports all those things you mention and is available on every platform worth mentioning. Don't blame the language when your vendor insists on locking you into their lousy compiler.
> obscure and often terribly non-intuitive syntax
Bullshit. C++ makes for a beautiful syntax. You just have no taste!
> overly complex and redundant idioms necessary to
> work around language shortcomings
C++ has no shortcomings. What are you talking about?
> they just switch to a more productive
> language...like the majority of the software
> industry is doing.
No they are not. The majority of the software industry are concerned with developing web applications. You can't do that in C++ because you do not want the stupid user to install anything but a browser. C++ is for real applications that run on your machine, like an application is supposed to.
Try this
Every once in a while people try to improve on C++. Usually it is those wet-behind-the-ears kids straight out of college who think that because C++ is too hard for them, it is a bad language. But real programmers just shrug and keep on coding in C++. Let the kids have their fun; they'll come around eventually when they want to write some real code. Maybe someday they'll discover that garbage collection is not necessary when you know who owns your memory and encapsulate allocation in logical places, like STL containers. They'll discover that C++ already has overridable operators, full (well, all that matters, anyhow) C compatibility, native compilation (VMs are for script kiddies), inline assembler, and in-built support for unit testing (called a debugger). And as for "Design by Contract", good luck getting any contracts in your new D.
> the GPL was written by Carl Marx
You ignorant savage! Everyone knows GPL was written by Orren Boyle.
> a=1, b=4, c=6, d=3, e=7
> what is ((a*b)+(c-a))-((d/f)+(c-a))
You don't need to refer back to the values at all. Just think of them as a vector f in function space G: (1,4,6,3,7). Then imagine an isomorphic mapping between integers 1 through 5 and the first five letters of the alphabet. The evaluation of any simple polynomial, such as the one presented above, is now trivial and is left as an exercise for the reader.
> Visit our website http://www.brainpills.com
I wrote in the URL as a joke, but I figured I might as well see if it exists. Believe it or not, it does. And from the front page (the FRONT PAGE) you can really find brain pills!!! So, should I laugh, scream, or cry?
Do you sometimes feel inadequate? Do you seem to forget important things? Would you like to be smarter, more educated, and get laid every day? Get our brain cache enlargement pills today! They are a wholly natural way of increasing your brain's "cache", or the very short term memory. Our pills contain no harmful chemicals, in fact, they contain no chemicals at all! Everything in them is completely natural and wholesome. Visit our website at http://www.brainpills.com for many wonderful success stories from our customers. Our pills work, so get yours today!
> Like, dude. That's what the propeller beanie is for.
Make sure you get the correct model of the propeller beanie. The kind with a motor inside. There are plenty of cheap imitations whose propeller only spins by convection. Such deplorable designs actually increase heat retention by obstructing upward heat flow. Of course, nothing beats water cooling for reducing heat in the head. A bucket of cold water is a low-tech, but effective method of obtaining positive results.
> * It takes 10,000 years to orbit the Sun.
> * Sedna spins on its axis once every 20 Earth-days.
So, in Sedna years, I am only 0.0273 years (498 days ) old! That explains a few things...
The discoveries said there _was_ water on mars, not that there is any now. It might still be there somewhere, but not in any quantity that can rust a gram of steel.
> Maybe they should have gotten that rust-proof coating after all.
You must mean "dust-proof coating". Given that there is no water on Mars and almost no oxygen, rust would not be much of a problem.
> My point is, that we re-create the same dwelling/software over and over again.
:). Earthworks are energy efficient because their large mass stores the heat as it leaves the living area. When heat leaves your house walls, it is gone into the air; when the heat goes into an earth wall, it creates a gradient which reduces further heat loss. In deserts, where night is very cold and day is very hot, the walls will actually feed back the heat stored during the day into the living area at night, drastically reducing your temperature swings.
Pehaps you are just oscillating around an optimal point.
> As for the energy efficiency, um, I'd have to call
> bullshit there. Part of a energy efficent dwelling
> has to do with the balance of breathability to airtightness.
Breathability has nothing to do with energy efficiency (although it is still worth considering if you want to keep breathing
> Mudhuts are not all that well sealed.
I am not talking about mud-and-wattle huts, which are about as energy efficient as a cardboard box, and less comfortable. I am talking about massive earth structures with three foot thick walls. See earthship.org, for an example.
It is rather sad to hear that being an individual is now considered evil.