Bingo. IT would get a lot more respect for its policies if (a) they didn't get in the way of doing our jobs rather than making us more productive, and (b) when stuff did go wrong despite the policies, IT actually fixed it and accepted responsibility.
In practice, I have never yet worked in any large organisation with a corporate IT department where this was the case, so my colleagues and I tend to be rather unsympathetic to claims that it's the IT guys whose jobs are on the line if things go wrong, etc. That clearly isn't true, because I've worked in plenty of places where some of the IT guys were totally incompetent yet continued to work there until leaving voluntarily after a long time.
Well, given that I don't live in the US, almost none of my savings and pensions are invested in the US, yet those accounts have dropped something like 1/3 of their value in recent weeks, I think we can safely say no, I did not mean that.
I can only surmise that the model/metaphor was poorly chosen or not well mapped onto the requirements.
Well, OK, perhaps you've never experienced it, but that doesn't mean it doesn't happen. What industries (in terms of application domains) have you worked in? The sort of thing I'm describing is not unusual when doing serious mathematical modelling and scientific data analysis, for example, where the underlying mathematics may be non-trivial, particularly once floating point and numerical analysis issues get into the picture.
Of course you still try to make the code as modular as possible, but if your basic building blocks only have any significance when combined together into a more meaningful whole, the basic level of testing effectively becomes low-level integration testing (or, if you prefer, unit testing of the combined modules at the point that they become self-sufficient). You can still apply unit testing principles to the building blocks, and it can still help to prevent "silly" errors, but in this sort of context, low-level unit tests alone can't provide that level of confidence that is so valuable from unit testing a more fine-grained modular design.
Please note that I'm not criticising the practice of unit testing. On the contrary, I completely agree that unit testing is a cost-effective way to improve code quality, and quite distinct from integration testing.
However, it seems to me that all the benefits you ascribe to TDD in your posts here are actually benefits derived from unit testing. The rest of TDD doesn't particularly help with any of these things, other than to the extent that it encourages development of unit tests, which of course you can do just as well without adopting the rest of TDD if you wish.
I guess we'll have to agree to disagree on your claim that "Most real world, usable software can be broken down into neat little boxes". Certainly some software can be developed entirely in this way, and modularity is in general a good thing. But I have seen plenty of examples, in plenty of different applications, where this simply isn't true, and the smallest independently meaningful, self-contained unit is quite large.
In such cases, you can't just ship 50% of a project and get 50% of the value out of it. To give the Slashdot-obligatory dubious car analogy: a vehicle that's 95% finished still isn't going to get you somewhere if no-one produces wheels to go on it. Similarly, software projects tend to be greater than the sum of their parts, because meeting 90% of the requirements but failing on the last 10% can easily make the whole project completely worthless to your client. Most software is not the kind of thing that comes in off-the-shelf boxes or one-time downloads, where you compare one version with the next using some dubious feature table showing how much better it is than the opposition, and missing the odd bullet mark isn't the end of the world.
You in fact made a perfect case for the argument that the code SHOULD have been developed test first, because then all the interdependencies you describe would not exist.
That's lovely, but what if the dependencies are implied by the requirements, rather than introduced artificially through insufficiently modular design? It doesn't matter what development process you follow, you still don't get to rewrite the requirements when they are inconvenient.
You make good points, but your choice of comparative examples seems a little ironic. If you're going to have a dig at people who make their money from talking rather than writing code, aren't Raymond and Stallman exactly the kind of person you're criticising?
That's like saying that seat belts can't save your life in every car accident so they're not worth wearing at all.
No, it's like saying that because seat belts won't save your life in every car accident, it's pretty dumb to drive around as if having an accident won't matter just because you're wearing a seat belt.
They're not, though, are they? We write documentation that is separate from code, because code is usually a poor place to provide overviews or describe the details of models and algorithms being implemented by that code. Automated tests are just more code in some form or another, and they have no special pass on this.
1) The are essential, not just helpful, at least, if you intend to produce software that works.
That clearly isn't true. Arguably the most robust software in the world is produced using the Cleanroom approach, which is almost the antithesis of TDD. Of course the typical constraints for the kind of development project that uses Cleanroom are rather extreme, but that doesn't make them any less valid a counter-example.
I tend to agree with you on [...] 2) No TDD or agile expert would include the word "anything" in this statement "When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything"
One of the problems I have with these "experts" is that while they may not actually say that, a lot of them certainly give that impression to people learning from them by not explicitly correcting the over-generalisation encouraged by their general presentation, and a lie of omission is still a lie. The very existence of that claim in the Slashdot summary here is a demonstration of the way a good probability can turn into an absolute in the mind of the impressionable student.
First, you write tests first, based on clear user stories.
Which is cute, except that a lot of real world software development doesn't fall into neat little boxes like that. You can test examples, but you can't test every possible document a user might type into your word processor, every possible data set you might collect with a scientific instrument, every possible configuration designed in a CAD application, or every possible state of a game world in a MMORPG. This matters, because a new "feature" might not make any sense in isolation, only in combination with other features to give it some context, so you can't just write a single, isolated test for its behaviour. The fact that dependencies between interacting features can be significant is why unit testing alone is insufficient as an approach to quality control.
While I completely respect your desire to learn, I advise against rushing out to read a whole book on the subject straight away.
The reason I say this is that unit testing is really a very simple idea: you should try to design your code so that you can test each module independently; implement simple, self-contained, automated tests for each part of the interface functionality; and then run your set of tests frequently, ideally between each change you make to the code. This certainly isn't foolproof, because it relies on having a good, comprehensive set of tests and usually it's impossible to cover everything. However, you can still help yourself to find most bugs quickly, and to identify very accurately and immediately where they come from, by using a good test suite. Of course there are some useful ideas and techniques that can help you to do these things more efficiently and reliably, but the basic principle is always the same.
People write whole "frameworks" to deal with this stuff and some books discuss them, but IME these frameworks are in that category of libraries that everyone seems to write but no-one seems to use. It is often simpler and faster to write your own that fits exactly into your particular project than to learn someone else's, create a dependency on external code, and then adapt it to your specific needs anyway.
Likewise, people write whole books on software development approaches like Test Driven Development, which are heavily based on unit tests. However, while there is plentiful objective evidence that quality can be improved by using unit tests, there is precious little beyond anecdotal evidence that anything other than consultants' incomes is improved by adopting TDD and the like. (If anyone disagrees with this, please spare us all the rant unless you can cite verifiable data to support what you're going to say.)
There are some good comments on unit testing in general software development books such as Code Complete, which you might find interesting and useful. But I advise steering clear of the specialist books on frameworks and methodologies built around unit testing, at least until you have enough experience to separate the snake oil from the real oil.
The obvious fix is to reward pharmaceutical companies financially for publishing all results.
Or simply compel them by law to publish all study results for any drugs under consideration for active use at any later stage. Their excuse for the enormous advantages they gain through patent protection and the like, and the borderline ethics of a lot of their business practices, is that R&D in a regulated industry is expensive. The cost of publishing failed tests as well would be absolutely negligible if the R&D costs as much overall as they keep telling us.
If your friend had given you his copy, or you had bought it used, that would be fine. But you did use the word "lent", which I took to mean that you were installing from your friend's copy while your friend was still using the software. That is against the law, and has been for a very long time, and the DRM is intended to prevent precisely that behaviour.
Need to undo 14 years of bad C++ practice, I guess.
Perhaps, but the nice thing about this particular change in programming style is that it doesn't have to be an all-or-nothing commitment. You can simply be aware of the issue, and write your new code in a more declarative style. It doesn't mean anyone else working with your code has to learn new language features or idioms, nor does it require you to change any existing code or modify any project-wide design decisions. You don't have to use it all the time, if using mutable variables seems a more natural way of expressing a particular algorithm. And while of course with experience you'll pick up a few useful tricks that help you to write better declarative code later, the earlier declarative code you wrote before you understood those ideas will still benefit somewhat from the basic approach. So go ahead and give it a try, even if it's only a little at first. If your experience is anything like mine, you'll be glad you did.
I'm sorry, I didn't realise anything in this thread was specific to C++. Exceptions exist, in broadly similar form, in almost every mainstream programming language in use today. The only major exception (no pun intended) is C.
As for using features other than as language designers intended... Your C++ focus seems a little ironic there. If no-one had ever tried using things like templates in other ways, a great deal of the power in modern C++ libraries would be missing. Whether the complexities of template metaprogramming and the current, almost fanatical emphasis on supporting it among the standards committee and Boost community are worth the technical and opportunity costs depends on your particular circumstances, but there is no denying that none of the people behind the language saw the idea coming or realised its potential.
I honestly don't understand all the negative feelings towards exceptions in the discussion here. Exceptions are just a tool in the programmer's toolbox, like loops and gotos and variables and functions. They define a certain behaviour, and there are certain overheads and savings in practice that you get if you choose to use that behaviour. There's no rule that says that as a programmer I may or may not use exceptions for any particular purpose or in any particular context. That is my choice as a software developer. Saying that I should not use it in certain ways is like saying a carpenter shouldn't use a saw in certain ways because the manufacturer of the saw doesn't make furniture that way themselves. It simply isn't the manufacturer's call. All that matters is whether the carpenter can use their choice of tools effectively to produce good results.
My friend lent me his copy of Crysis right after I upgraded my PC, but I never installed it specifically because of the packaged DRM.
That sounds like the DRM doing its job to me, so I can't say I'm sympathetic.
I, on the other hand, have literally just returned ten minutes ago from looking for a new game at my local store, having decided not to buy either this very game, nor another high profile title I'd been considering, after reading the small print. I won't rip them off instead, and I do have a legal copy of the original Crysis, but I have become increasingly irritated by companies treating me like a criminal, and I choose not to support them any more. There are enough enjoyable games that don't do this sort of thing to amuse me for several lifetimes, and I will buy some of those instead.
The same goes for things with abusive "anti-cheating" technologies, as well. I run various security software on my computer to stop anyone else's software doing things without my consent, and games don't get a free pass on that. I don't see the attraction of cheating using bots and the like myself, and for on-line gameplay I would rather just find servers where other people don't run bots all the time than put up with unknown software that is behaviourly indistinguishable from malware scanning unrelated parts of my computer and sending my data off to who-knows-who over the Internet to prove that I am not cheating.
For the record, I was just thinking at the store that it would be nice if game reviewers made a point of describing any DRM and on-line gameplay restrictions as part of the review, and I thank Soulskill for doing so in this case.
No-one said anything about being smarter than you. Don't take things so personally.
That said, you might like to consider that mathematical notation has diverged from natural language for practical reasons, and programming languages have a lot in common with mathematical notation.
I agree with you that using basic higher order functions can make things much cleaner, but FWIW I'm not a big fan of list comprehension syntax, in Python or otherwise. It tends to be horribly cumbersome. In simple cases, such as your example, a typical functional programming language would just write something like this:
taxes = map tax_calc items
with no repeated extra variable that doesn't actually do anything. For more complicated comprehensions, an explicit series of filter/map/reduce type steps seems clearer to me personally than forcing a hybrid into a new syntax for no particular benefit. In short, list comprehensions are syntactic sugar that don't actually make things any easier to read to my eyes. YMMV, of course, and obviously in languages that have comprehensions but not first class functions your choices are limited (and still better than writing out all the loop logic manually).
People like you kill debates and make other people hesitate even though many of them know a lot more than you do on any given subject.
I appreciate the moral support, but I've taught far worse than that AC in my time. The ones who go around f'ing this and s'ing that are invariably all bluster, usually uncomfortable with not being the "smartest person in the room", perhaps for the first time. After a while, they realise that there are always a lot of smarter, more experienced people in the world, and that perhaps listening to other views is good even if they don't always agree with them.
And yes, I have been around a fairly long time in the programmng world. Long enough to know that a lot of people who balk at using an exception don't bat an eyelid at using a break/continue, or an early return statement, or even a goto, yet can't quite explain logically why these are OK but using the exception is a cardinal sin. Some of them still write convoluted loop logic with early exit flags, despite the horrendous clutter it introduces in complex cases, because they have an almost religious belief in structured programming and the single entry-single exit rule, but again, they never quite know why it's supposed to be better. There's not much you can do to help someone with a closed mind, but you can at least show them options for when they learn to open it.
Exceptions are called "exceptions" for a reason. If you have code that would be called in the normal flow of a program, it should be in a method or function of its own.
But what is the "normal flow" of a program? I have never seen a useful, universal definition of "normal" vs. "exceptional" in this context. The best approximation I have seen came from, IIRC, Herb Sutter, who described things in terms of whether pre-condition, post-condition or invariant contracts are violated. But then of course you have to consider whether it's appropriate to write a function with a simpler interface and deliberately force the more complicated failure cases into failed post-conditions that become exceptions.
In other words, it's easy to quote dogma about normal flow and truly exceptional cases, but it's a whole lot harder to make the words actually mean something specific.
My guess is that you did not go to school and learned programming on your own, which is fine, but please, understand that in this case, you are wrong.
Thanks. I'll just take my academic CS qualifications, many years of programming, and numerous successful long-term projects I've worked on, and assume everything I've learned from that experience is wrong because someone on Slashdot told me so.
Curiously, one of my responsibilities these days is providing training for less experienced developers. One of the first things I do when we talk about dealing with faults, failures and errors is to show that there are several very different approaches you can take. One of the next things I do is explain that this area is full of more dogmatic rules than just about any other in software development, and almost all of them should be broken at some point. A lot of the guys I work with have come from a background using something like Java or.Net-based languages and have never seen ideas like the Erlang "let the thread die" model, or the use of monads in Haskell. When I ask a few warm-up questions, they'll quote me all kinds of rules and dogma just like several of the responses in this thread, yet they rarely have any reason beyond blind faith to believe what someone once told them. By the time we've finished, pretty much the one thing everyone always agrees on is that all of these techniques are merely tools, and dogmatic adherence to rules is never a substitute for looking at what reads most naturally, performs best, leaves the smallest scope for errors, and similar criteria. You can only judge those things when you're looking at real code for a specific problem, knowing the programming language, preferences of the development team, and so on.
Exceptions are much like GOTO in that they can literally skip out of code and skip back in.
You should come to one of my courses some time. One thing we talk about, in considerable detail, is the important differences between exceptions and gotos.
In any case, your final comment has betrayed your real feelings:
You don't realize it but it allows you to create spaghetti code really easily, which might be easier to begin with but will ultimately make your code hard to follow when it starts to become larger.
It's not the particular exception vs. goto argument we were talking about here that bothers you. You just don't like exceptions at all, do you?
I've got a few successful, multi-million line projects behind me that say you're wrong on the claim above, BTW. Using exceptions can be very helpful for keeping your error handling systematic in code bases on that scale. It requires a little forethought, as all architectural issues on that scale do, but in most cases it is strongly preferable to relying on manual error handling using things like propagation of return codes.
You seem to have taken a post that you disagreed with, and instead of actually providing any information about why you feel it is incorrect (such as a verifiable counter-example to the notes on efficiency gains and losses I provided), you have repeated urban legends about exception performance that have been obsolete on good platforms for several years. You have also engaged in an ad hominem attack, and in making generic statements about "handling exceptions" without defining in any useful way what you consider to be exceptional. Finally, you have attempted, without giving any reason, to narrow the discussion to a small number of very similar VM-based languages, which may or may not have performance characteristics that match other languages; I don't program on those platforms much myself, but even I am aware that one of them has been notorious for its slow exception mechanism in the past, and notes from another post suggest that this may still be the case.
I like my code just fine, thank you, and the way I write it is based on using the right tool for the job. That means making a decision about whether to use exceptions (or not) is based on readability/maintainability of the code and objective evidence about performance, not on dogma and hear'say.
Unfortunately, test-driven design is not a silver bullet, unless you're lucky enough to have a finite problem space where you can achieve 100% test coverage, which almost no-one does, and you can consistently write perfect test code, which would be surprising if you're worried enough about your normal code to write all those tests in the first place.
In the absence of such unrealistic guarantees, TDD lies somewhere between a useful addition to your coding practices and snake oil, depending on the realism and honesty of the person advocating/implementing it. Either case, it is not a substitute for good documentation and commenting.
Exceptions are not meant for intentional flow control, they are for exceptions.
Says who?
Exceptions are (in almost all implementations) much slower and you would never want to use them in place of a goto in, say, a core loop where the goto case happens a significant portion of the time.
Not so fast, hotshot. Techniques for implementing exceptions efficiently have been known for quite some time now. There are still necessarily overheads involved on the occasions when an exception is thrown and caught, of course. However, there can also be savings from skipping over redundant code efficiently in exceptional cases, which may (or may not) outweigh the overheads. Moreover, in simple cases where the general exception mechanism would be overweight because the exception is thrown and caught locally, how do you know your compiler/interpreter isn't just optimising it to a goto anyway, since it can see the entire picture all in one place? You really need to look at the profiling results if the performance matters.
Having an expression and a statement is more for an academic point of view than real practical use.
Nonsense. Moving towards a more declarative programming style is an effective way to reduce programmer errors and improve code readability. That includes initialising data using expressions and, ideally, marking it immutable, rather than starting with uninitialised variables and then setting their values via assignment statements. If your “variables” can't, then it's always easy to work out where each value came from, and you can never forget to initialise a variable, accidentally change its value, or reuse it for a different purpose later.
Even in primarily imperative programming languages, which mostly aren't as expressive in this respect as their functional counterparts, you can follow the basic principle most of the time with minimal effort. Try it: your code will almost certainly wind up less buggy and easier to maintain.
Bingo. IT would get a lot more respect for its policies if (a) they didn't get in the way of doing our jobs rather than making us more productive, and (b) when stuff did go wrong despite the policies, IT actually fixed it and accepted responsibility.
In practice, I have never yet worked in any large organisation with a corporate IT department where this was the case, so my colleagues and I tend to be rather unsympathetic to claims that it's the IT guys whose jobs are on the line if things go wrong, etc. That clearly isn't true, because I've worked in plenty of places where some of the IT guys were totally incompetent yet continued to work there until leaving voluntarily after a long time.
Well, given that I don't live in the US, almost none of my savings and pensions are invested in the US, yet those accounts have dropped something like 1/3 of their value in recent weeks, I think we can safely say no, I did not mean that.
What is the fscking cloud?
It's just a shorthand for where all the corporate CIOs' heads are right now: up in the clouds.
Don't worry, their feet will be brought back to the ground in short order as a result of the current world financial problems.
I can only surmise that the model/metaphor was poorly chosen or not well mapped onto the requirements.
Well, OK, perhaps you've never experienced it, but that doesn't mean it doesn't happen. What industries (in terms of application domains) have you worked in? The sort of thing I'm describing is not unusual when doing serious mathematical modelling and scientific data analysis, for example, where the underlying mathematics may be non-trivial, particularly once floating point and numerical analysis issues get into the picture.
Of course you still try to make the code as modular as possible, but if your basic building blocks only have any significance when combined together into a more meaningful whole, the basic level of testing effectively becomes low-level integration testing (or, if you prefer, unit testing of the combined modules at the point that they become self-sufficient). You can still apply unit testing principles to the building blocks, and it can still help to prevent "silly" errors, but in this sort of context, low-level unit tests alone can't provide that level of confidence that is so valuable from unit testing a more fine-grained modular design.
Please note that I'm not criticising the practice of unit testing. On the contrary, I completely agree that unit testing is a cost-effective way to improve code quality, and quite distinct from integration testing.
However, it seems to me that all the benefits you ascribe to TDD in your posts here are actually benefits derived from unit testing. The rest of TDD doesn't particularly help with any of these things, other than to the extent that it encourages development of unit tests, which of course you can do just as well without adopting the rest of TDD if you wish.
I guess we'll have to agree to disagree on your claim that "Most real world, usable software can be broken down into neat little boxes". Certainly some software can be developed entirely in this way, and modularity is in general a good thing. But I have seen plenty of examples, in plenty of different applications, where this simply isn't true, and the smallest independently meaningful, self-contained unit is quite large.
In such cases, you can't just ship 50% of a project and get 50% of the value out of it. To give the Slashdot-obligatory dubious car analogy: a vehicle that's 95% finished still isn't going to get you somewhere if no-one produces wheels to go on it. Similarly, software projects tend to be greater than the sum of their parts, because meeting 90% of the requirements but failing on the last 10% can easily make the whole project completely worthless to your client. Most software is not the kind of thing that comes in off-the-shelf boxes or one-time downloads, where you compare one version with the next using some dubious feature table showing how much better it is than the opposition, and missing the odd bullet mark isn't the end of the world.
You in fact made a perfect case for the argument that the code SHOULD have been developed test first, because then all the interdependencies you describe would not exist.
That's lovely, but what if the dependencies are implied by the requirements, rather than introduced artificially through insufficiently modular design? It doesn't matter what development process you follow, you still don't get to rewrite the requirements when they are inconvenient.
You make good points, but your choice of comparative examples seems a little ironic. If you're going to have a dig at people who make their money from talking rather than writing code, aren't Raymond and Stallman exactly the kind of person you're criticising?
That's like saying that seat belts can't save your life in every car accident so they're not worth wearing at all.
No, it's like saying that because seat belts won't save your life in every car accident, it's pretty dumb to drive around as if having an accident won't matter just because you're wearing a seat belt.
Challenge 1) Create a good design from scratch. Lots of folks can do this.
I wish I worked in your world! In mine, lots of folks think they can do good design, but most haven't the first clue about what good design is.
They're not, though, are they? We write documentation that is separate from code, because code is usually a poor place to provide overviews or describe the details of models and algorithms being implemented by that code. Automated tests are just more code in some form or another, and they have no special pass on this.
1) The are essential, not just helpful, at least, if you intend to produce software that works.
That clearly isn't true. Arguably the most robust software in the world is produced using the Cleanroom approach, which is almost the antithesis of TDD. Of course the typical constraints for the kind of development project that uses Cleanroom are rather extreme, but that doesn't make them any less valid a counter-example.
I tend to agree with you on [...] 2) No TDD or agile expert would include the word "anything" in this statement "When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything"
One of the problems I have with these "experts" is that while they may not actually say that, a lot of them certainly give that impression to people learning from them by not explicitly correcting the over-generalisation encouraged by their general presentation, and a lie of omission is still a lie. The very existence of that claim in the Slashdot summary here is a demonstration of the way a good probability can turn into an absolute in the mind of the impressionable student.
First, you write tests first, based on clear user stories.
Which is cute, except that a lot of real world software development doesn't fall into neat little boxes like that. You can test examples, but you can't test every possible document a user might type into your word processor, every possible data set you might collect with a scientific instrument, every possible configuration designed in a CAD application, or every possible state of a game world in a MMORPG. This matters, because a new "feature" might not make any sense in isolation, only in combination with other features to give it some context, so you can't just write a single, isolated test for its behaviour. The fact that dependencies between interacting features can be significant is why unit testing alone is insufficient as an approach to quality control.
While I completely respect your desire to learn, I advise against rushing out to read a whole book on the subject straight away.
The reason I say this is that unit testing is really a very simple idea: you should try to design your code so that you can test each module independently; implement simple, self-contained, automated tests for each part of the interface functionality; and then run your set of tests frequently, ideally between each change you make to the code. This certainly isn't foolproof, because it relies on having a good, comprehensive set of tests and usually it's impossible to cover everything. However, you can still help yourself to find most bugs quickly, and to identify very accurately and immediately where they come from, by using a good test suite. Of course there are some useful ideas and techniques that can help you to do these things more efficiently and reliably, but the basic principle is always the same.
People write whole "frameworks" to deal with this stuff and some books discuss them, but IME these frameworks are in that category of libraries that everyone seems to write but no-one seems to use. It is often simpler and faster to write your own that fits exactly into your particular project than to learn someone else's, create a dependency on external code, and then adapt it to your specific needs anyway.
Likewise, people write whole books on software development approaches like Test Driven Development, which are heavily based on unit tests. However, while there is plentiful objective evidence that quality can be improved by using unit tests, there is precious little beyond anecdotal evidence that anything other than consultants' incomes is improved by adopting TDD and the like. (If anyone disagrees with this, please spare us all the rant unless you can cite verifiable data to support what you're going to say.)
There are some good comments on unit testing in general software development books such as Code Complete, which you might find interesting and useful. But I advise steering clear of the specialist books on frameworks and methodologies built around unit testing, at least until you have enough experience to separate the snake oil from the real oil.
The obvious fix is to reward pharmaceutical companies financially for publishing all results.
Or simply compel them by law to publish all study results for any drugs under consideration for active use at any later stage. Their excuse for the enormous advantages they gain through patent protection and the like, and the borderline ethics of a lot of their business practices, is that R&D in a regulated industry is expensive. The cost of publishing failed tests as well would be absolutely negligible if the R&D costs as much overall as they keep telling us.
If your friend had given you his copy, or you had bought it used, that would be fine. But you did use the word "lent", which I took to mean that you were installing from your friend's copy while your friend was still using the software. That is against the law, and has been for a very long time, and the DRM is intended to prevent precisely that behaviour.
Need to undo 14 years of bad C++ practice, I guess.
Perhaps, but the nice thing about this particular change in programming style is that it doesn't have to be an all-or-nothing commitment. You can simply be aware of the issue, and write your new code in a more declarative style. It doesn't mean anyone else working with your code has to learn new language features or idioms, nor does it require you to change any existing code or modify any project-wide design decisions. You don't have to use it all the time, if using mutable variables seems a more natural way of expressing a particular algorithm. And while of course with experience you'll pick up a few useful tricks that help you to write better declarative code later, the earlier declarative code you wrote before you understood those ideas will still benefit somewhat from the basic approach. So go ahead and give it a try, even if it's only a little at first. If your experience is anything like mine, you'll be glad you did.
I'm sorry, I didn't realise anything in this thread was specific to C++. Exceptions exist, in broadly similar form, in almost every mainstream programming language in use today. The only major exception (no pun intended) is C.
As for using features other than as language designers intended... Your C++ focus seems a little ironic there. If no-one had ever tried using things like templates in other ways, a great deal of the power in modern C++ libraries would be missing. Whether the complexities of template metaprogramming and the current, almost fanatical emphasis on supporting it among the standards committee and Boost community are worth the technical and opportunity costs depends on your particular circumstances, but there is no denying that none of the people behind the language saw the idea coming or realised its potential.
I honestly don't understand all the negative feelings towards exceptions in the discussion here. Exceptions are just a tool in the programmer's toolbox, like loops and gotos and variables and functions. They define a certain behaviour, and there are certain overheads and savings in practice that you get if you choose to use that behaviour. There's no rule that says that as a programmer I may or may not use exceptions for any particular purpose or in any particular context. That is my choice as a software developer. Saying that I should not use it in certain ways is like saying a carpenter shouldn't use a saw in certain ways because the manufacturer of the saw doesn't make furniture that way themselves. It simply isn't the manufacturer's call. All that matters is whether the carpenter can use their choice of tools effectively to produce good results.
My friend lent me his copy of Crysis right after I upgraded my PC, but I never installed it specifically because of the packaged DRM.
That sounds like the DRM doing its job to me, so I can't say I'm sympathetic.
I, on the other hand, have literally just returned ten minutes ago from looking for a new game at my local store, having decided not to buy either this very game, nor another high profile title I'd been considering, after reading the small print. I won't rip them off instead, and I do have a legal copy of the original Crysis, but I have become increasingly irritated by companies treating me like a criminal, and I choose not to support them any more. There are enough enjoyable games that don't do this sort of thing to amuse me for several lifetimes, and I will buy some of those instead.
The same goes for things with abusive "anti-cheating" technologies, as well. I run various security software on my computer to stop anyone else's software doing things without my consent, and games don't get a free pass on that. I don't see the attraction of cheating using bots and the like myself, and for on-line gameplay I would rather just find servers where other people don't run bots all the time than put up with unknown software that is behaviourly indistinguishable from malware scanning unrelated parts of my computer and sending my data off to who-knows-who over the Internet to prove that I am not cheating.
For the record, I was just thinking at the store that it would be nice if game reviewers made a point of describing any DRM and on-line gameplay restrictions as part of the review, and I thank Soulskill for doing so in this case.
No-one said anything about being smarter than you. Don't take things so personally.
That said, you might like to consider that mathematical notation has diverged from natural language for practical reasons, and programming languages have a lot in common with mathematical notation.
I agree with you that using basic higher order functions can make things much cleaner, but FWIW I'm not a big fan of list comprehension syntax, in Python or otherwise. It tends to be horribly cumbersome. In simple cases, such as your example, a typical functional programming language would just write something like this:
with no repeated extra variable that doesn't actually do anything. For more complicated comprehensions, an explicit series of filter/map/reduce type steps seems clearer to me personally than forcing a hybrid into a new syntax for no particular benefit. In short, list comprehensions are syntactic sugar that don't actually make things any easier to read to my eyes. YMMV, of course, and obviously in languages that have comprehensions but not first class functions your choices are limited (and still better than writing out all the loop logic manually).
People like you kill debates and make other people hesitate even though many of them know a lot more than you do on any given subject.
I appreciate the moral support, but I've taught far worse than that AC in my time. The ones who go around f'ing this and s'ing that are invariably all bluster, usually uncomfortable with not being the "smartest person in the room", perhaps for the first time. After a while, they realise that there are always a lot of smarter, more experienced people in the world, and that perhaps listening to other views is good even if they don't always agree with them.
And yes, I have been around a fairly long time in the programmng world. Long enough to know that a lot of people who balk at using an exception don't bat an eyelid at using a break/continue, or an early return statement, or even a goto, yet can't quite explain logically why these are OK but using the exception is a cardinal sin. Some of them still write convoluted loop logic with early exit flags, despite the horrendous clutter it introduces in complex cases, because they have an almost religious belief in structured programming and the single entry-single exit rule, but again, they never quite know why it's supposed to be better. There's not much you can do to help someone with a closed mind, but you can at least show them options for when they learn to open it.
Exceptions are called "exceptions" for a reason. If you have code that would be called in the normal flow of a program, it should be in a method or function of its own.
But what is the "normal flow" of a program? I have never seen a useful, universal definition of "normal" vs. "exceptional" in this context. The best approximation I have seen came from, IIRC, Herb Sutter, who described things in terms of whether pre-condition, post-condition or invariant contracts are violated. But then of course you have to consider whether it's appropriate to write a function with a simpler interface and deliberately force the more complicated failure cases into failed post-conditions that become exceptions.
In other words, it's easy to quote dogma about normal flow and truly exceptional cases, but it's a whole lot harder to make the words actually mean something specific.
My guess is that you did not go to school and learned programming on your own, which is fine, but please, understand that in this case, you are wrong.
Thanks. I'll just take my academic CS qualifications, many years of programming, and numerous successful long-term projects I've worked on, and assume everything I've learned from that experience is wrong because someone on Slashdot told me so.
Curiously, one of my responsibilities these days is providing training for less experienced developers. One of the first things I do when we talk about dealing with faults, failures and errors is to show that there are several very different approaches you can take. One of the next things I do is explain that this area is full of more dogmatic rules than just about any other in software development, and almost all of them should be broken at some point. A lot of the guys I work with have come from a background using something like Java or .Net-based languages and have never seen ideas like the Erlang "let the thread die" model, or the use of monads in Haskell. When I ask a few warm-up questions, they'll quote me all kinds of rules and dogma just like several of the responses in this thread, yet they rarely have any reason beyond blind faith to believe what someone once told them. By the time we've finished, pretty much the one thing everyone always agrees on is that all of these techniques are merely tools, and dogmatic adherence to rules is never a substitute for looking at what reads most naturally, performs best, leaves the smallest scope for errors, and similar criteria. You can only judge those things when you're looking at real code for a specific problem, knowing the programming language, preferences of the development team, and so on.
Exceptions are much like GOTO in that they can literally skip out of code and skip back in.
You should come to one of my courses some time. One thing we talk about, in considerable detail, is the important differences between exceptions and gotos.
In any case, your final comment has betrayed your real feelings:
You don't realize it but it allows you to create spaghetti code really easily, which might be easier to begin with but will ultimately make your code hard to follow when it starts to become larger.
It's not the particular exception vs. goto argument we were talking about here that bothers you. You just don't like exceptions at all, do you?
I've got a few successful, multi-million line projects behind me that say you're wrong on the claim above, BTW. Using exceptions can be very helpful for keeping your error handling systematic in code bases on that scale. It requires a little forethought, as all architectural issues on that scale do, but in most cases it is strongly preferable to relying on manual error handling using things like propagation of return codes.
You seem to have taken a post that you disagreed with, and instead of actually providing any information about why you feel it is incorrect (such as a verifiable counter-example to the notes on efficiency gains and losses I provided), you have repeated urban legends about exception performance that have been obsolete on good platforms for several years. You have also engaged in an ad hominem attack, and in making generic statements about "handling exceptions" without defining in any useful way what you consider to be exceptional. Finally, you have attempted, without giving any reason, to narrow the discussion to a small number of very similar VM-based languages, which may or may not have performance characteristics that match other languages; I don't program on those platforms much myself, but even I am aware that one of them has been notorious for its slow exception mechanism in the past, and notes from another post suggest that this may still be the case.
I like my code just fine, thank you, and the way I write it is based on using the right tool for the job. That means making a decision about whether to use exceptions (or not) is based on readability/maintainability of the code and objective evidence about performance, not on dogma and hear'say.
Unfortunately, test-driven design is not a silver bullet, unless you're lucky enough to have a finite problem space where you can achieve 100% test coverage, which almost no-one does, and you can consistently write perfect test code, which would be surprising if you're worried enough about your normal code to write all those tests in the first place.
In the absence of such unrealistic guarantees, TDD lies somewhere between a useful addition to your coding practices and snake oil, depending on the realism and honesty of the person advocating/implementing it. Either case, it is not a substitute for good documentation and commenting.
Exceptions are not meant for intentional flow control, they are for exceptions.
Says who?
Exceptions are (in almost all implementations) much slower and you would never want to use them in place of a goto in, say, a core loop where the goto case happens a significant portion of the time.
Not so fast, hotshot. Techniques for implementing exceptions efficiently have been known for quite some time now. There are still necessarily overheads involved on the occasions when an exception is thrown and caught, of course. However, there can also be savings from skipping over redundant code efficiently in exceptional cases, which may (or may not) outweigh the overheads. Moreover, in simple cases where the general exception mechanism would be overweight because the exception is thrown and caught locally, how do you know your compiler/interpreter isn't just optimising it to a goto anyway, since it can see the entire picture all in one place? You really need to look at the profiling results if the performance matters.
Having an expression and a statement is more for an academic point of view than real practical use.
Nonsense. Moving towards a more declarative programming style is an effective way to reduce programmer errors and improve code readability. That includes initialising data using expressions and, ideally, marking it immutable, rather than starting with uninitialised variables and then setting their values via assignment statements. If your “variables” can't, then it's always easy to work out where each value came from, and you can never forget to initialise a variable, accidentally change its value, or reuse it for a different purpose later.
Even in primarily imperative programming languages, which mostly aren't as expressive in this respect as their functional counterparts, you can follow the basic principle most of the time with minimal effort. Try it: your code will almost certainly wind up less buggy and easier to maintain.