Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

What language, in your opinion, allows the average programmer to output features with the least amount of hard-to-find bugs? This is of course, a very broad question, and I'm interested in very broad and general answers and wisdoms.

Personally I find that I spend very little time looking for strange bugs in Java and C# programs, while C++ code has its distinct set of recurring bugs, and Python/similar has its own set of common and silly bugs that would be detected by the compiler in other languages.

Also I find it hard to consider functional languages in this regard, because I've never seen a big and complex program written in entirely functional code. Your input please.

Edit: Completely arbitrary clarification of hard-to-find bug: Takes more than 15 minutes to reproduce, or more than 1 hour to find cause of and fix.

Forgive me if this is a duplicate, but I didn't find anything on this specific topic.

share|improve this question

closed as not constructive by gnat, Tom Squires, Walter, Glenn Nelson, Martijn Pieters Jan 22 '13 at 13:20

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.If this question can be reworded to fit the rules in the help center, please edit the question.

8  
I'd like to see some research done into this topic! Not just "my anecdotal evidence suggests that the only language I know is king" but bug rates from large projects, and so on. –  Frank Shearar Dec 1 '10 at 11:00
    
@Frank .. if you had A LOT (and I do mean A LOT) of time, you could probably mine some statistics out of ohloh, provided you could identify patches that fixed bugs from thousands of code repositories. –  Tim Post Dec 1 '10 at 11:47
    
The one where only comments are allowed. No other instructions :) –  Victor Hurdugaci Dec 1 '10 at 12:02
4  
I think "hard-to-find" needs to be clarified. Your question and most of the answers seem to define "hard-to-find" as being equivalent to "not caught by the compiler." You mention python as having silly bugs that would be detected by the compiler. Fair enough. But those silly bugs usually aren't that hard to find. Certainly, they aren't in the same category as C++ bugs deriving from say freeing memory too soon. –  Winston Ewert Dec 1 '10 at 15:15
    
@Winston Agree. –  Magnus Wolffelt Dec 1 '10 at 16:21
show 12 more comments

12 Answers

up vote 49 down vote accepted

The more powerful the type system of the language, the more bugs will be caught at the compile time itself.

The following figure compares some of the well known programming languages in terms of the power, simplicity, and safety of their type systems. [ Source ]

alt text

share|improve this answer
8  
This is brilliant! –  user8685 Dec 1 '10 at 13:58
5  
I couldn't find Common Lisp in the graphic: (let ((itbe '())) ... )... –  duros Dec 1 '10 at 14:30
6  
What? There wasn't any space left on the left side for PHP? –  pestaa Dec 1 '10 at 16:39
5  
C# allows safe pointers: all pointer arithmetic is checked. Therefore, I believe it should be up there with Java. –  Alex ten Brink Dec 1 '10 at 16:57
9  
@missingfaktor: I think C# is not well positioned. C# allows and promotes safter programming styles. It should not be measured by the worst thing it allows. –  back2dos Dec 1 '10 at 17:44
show 25 more comments

In my opinion Haskell helps you avoid some common sources of errors:

  • it's purely functional: functions can not have (unintentional) side-effects and thus makes multicore programming easier and less error-prone
  • it is strongly typed: you can not e.g. accidentally mix bool, char, int and float values
  • it's statically typed: many programming errors are catched at compile time
  • null is not part of value type definitions: by this you avoid the billion dollar mistake
  • there are a lot of ready-made higher-order functions which you can reuse instead of writing your own, possibly faulty implementation
  • it has a garbage collector: memory errors are almost eleminated (except for "space leaks" due to it's lazy evaluation strategy)
share|improve this answer
6  
I won't downvote this, but I'm tempted to because it doesn't fit the criteria. It's supposed to allow "the average programmer to output features" with a minimal bug count, but the average programmer, to put it bluntly, can't make heads or tails of Haskell in the first place. –  Mason Wheeler Dec 1 '10 at 12:51
5  
Many good points, but while removing some classes of error (unintended side effects, unexpected type conversions) Haskell adds a whole new class of error: space leaks. (Also although there is no null, there is undefined, which is a member of every type.) –  j_random_hacker Dec 1 '10 at 13:15
5  
@Mason: If you don't write in it, you can't have bugs int it :) –  Michael K Dec 1 '10 at 13:38
1  
I guess there's no such thing as a free lunch - you can have easy-to-find bugs, or easy-to-write code, but not both :) –  Benjol Dec 2 '10 at 5:52
5  
@Mason what exactly is an “average programmer”? The question begins with “what programming language...”, not “which among C, C++ and java...” ;) –  Agos Dec 2 '10 at 9:19
show 7 more comments

Traditionally the hardest to find bugs are race-conditions in multi-threaded applications as they are

  • almost impossible to reproduce
  • can be very subtle

Hence you need languages that manage the parallism for you as much and unintrusively as possible. These are not yet mainstream. Java does some, but leave you with the hard part.

To my understanding, you need a functional language since the "no sideeffects" is the thing that in the first place makes the two bullet points go away. I've seen that work is ongoing in transparently making Haskell an efficient multi-thread language, and I believe Fortress is designed from the ground up to be an efficient parallel language.


Edit: In Java Executors handle even more of the hard parts. You need to make the individual tasks conform to the Callable interface.

share|improve this answer
2  
++ Race conditions. You can say that again. –  Mike Dunlavey Dec 1 '10 at 18:12
    
Yeah. Bear in mind that parallel computing in general is hard, even with language assistance. (Common Lisp macros are hard, despite a lot of language support, because what they do is very powerful. Same principal.) –  David Thornley Dec 1 '10 at 18:28
    
What about Erlang? –  Malfist Dec 1 '10 at 21:43
    
@Malfist, I do not know enough about Erlang to answer that. Perhaps you should open a question if you really want to know? –  user1249 Dec 1 '10 at 23:19
1  
Erlang is a functional programming designed to make multithreading simple and safe. You don't share variables, you pass messages. Read it's wikipedia page. –  Malfist Dec 3 '10 at 14:15
show 7 more comments

Ada is designed so that as much as possible is caught at compile-time rather than run-time. What this means is that it often takes about 10x longer to get a program in Ada to compile than the equivalent would in Java say, but when it does compile you can be much more confident that whole classes of bugs will not manifest themselves when the program's run.

share|improve this answer
3  
+1 for noticing, correctly, that Ada catches things in the compiler that other languages ignore. -1 for the assertion that this means it takes 10x longer to get an Ada program to compile. Ada rewards the programmer who DESIGNS!!! his code, who THINKS!!! about what he is doing before he starts madly typing. My personal experience, doing production programming in Ada for defense work, was that it didn't take significantly longer to get Ada code to compile than it takes C/C++ or FORTRAN, but the Ada code had significantly less trouble later. Pratt & Whitney noticed something similar. –  John R. Strohm Dec 1 '10 at 14:06
1  
@john r strohm, from what I understand, he is not talking about time it takes for the compiler to compile code, rather the time to make the code compilable. –  Malfist Dec 1 '10 at 21:39
    
oh agreed about getting the code compilable. I can remember quite a lot of sexist comments made by programmers learning the language about its nit picking. Usually along the lines of Well, if you do name a language after a woman... –  Ptolemy Dec 2 '10 at 12:01
    
@Ptolemy, if boats can be named after women (except apparently for US carriers) then programming languages can too. Rather have it named "Ada" than "USS Ronald Reagan" :) –  user1249 Jul 4 '11 at 9:13
1  
Once I got over the learning curve, I actually got pretty fast at writing Ada code -- after I had spent a good deal of time thinking through the design. Ada is most definitely NOT a hacker's language. I work in Java nowadays, and some of the stuff I'm seeing in my current projects actually makes me miss Ada a little bit (never thought I'd say that). –  James Adam Jan 22 '13 at 16:13
show 1 more comment

First a definition: a hard-to-find bug, as I understand it, is a bug that can be reproduced but the cause is hard to find.

Probably the most important aspect is what I would call narrowness, i.e. how far can a bug escape, how large is the scope a bug can potentially influence. In languages like C, a bug, e.g. a negative array index or uninitialized pointer, can affect literally everything everywhere in the whole program, so in the worst case, you have to check everything everywhere to find the source of your problem.

Good languages in that regard support access modifiers and enforce them in a way that makes it hard or impossible to bypass them. Good languages encourage you to limit the scope of your variables, instead of making it too easy to have global variables (e.g. "everything not explicitely declared is a global variable with a default type and value").

The second important aspect is concurrency. Race conditions are generally hard to reproduce and therefore hard to find. Good languages offer easy-to-use synchronisation mechanisms, and their standard libs are thread safe where necessary.

This already completes my list; other things like strong typing help to catch bugs at compile time, but those bugs probably wouldn't be hard to find later.

Considering all that, I'd say that Java and C#, and many other languages in the JVM and .net world, are suitable to avoid hard-to-find bugs.

share|improve this answer
    
Manual locking might look to be an "easy-to-use synchronisation mechanism" but it's really only "simple to use but you're in for fun times as you chase down that deadlock". And, well, you can do Actor-based concurrency in quite a few languages. –  Frank Shearar Dec 1 '10 at 15:23
    
Frank: at least locking is simple enough so everyone can do it without spending days, figuring out which API to use etc. –  user281377 Dec 1 '10 at 15:39
    
Then there's the viewpoint that a concurrency solution that's "simple enough so everyone can do it" is like giving table saws to pre-schoolers. –  David Thornley Dec 1 '10 at 18:30
    
@David: I see your point, but in many cases, a simple solution is really all that it takes. For example, consider a servlet used by only a handful of users, which has to use a shared resource (e.g. the database connection). Without synchronisation, race conditions happen every now and then; but it's not exactly rocket science to put all database access operations into a synchronized(connection){} block. –  user281377 Dec 1 '10 at 22:30
add comment

What language, in your opinion, allows the average programmer to output features with the least amount of hard-to-find bugs?

In my opinion, Delphi. Being based on Pascal, the language is simple and intuitive enough for the average programmer (or even inexperienced coders) to pick up easily, and its rich tool and library support make most bugs easy to find.

  • Strong typing and a strict compiler that catches many common errors.
  • Intuitive syntax that doesn't encourage common errors. ("The World's Last Bug," if (alert = RED) {LaunchNukes;}, will not compile, for example.)
  • A well-designed object model that eliminates many of the common C++ OOP errors.
  • Bounds checking and range checking built in to the language, drastically reducing the chances of security problems.
  • Probably the fastest compiler known to man, which increases your productivity and makes it harder to lose your train of thought while waiting on a build.
  • The debugger Visual Studio's debugger wants to be like when it grows up.
  • Leak tracking built directly in to the memory manager, making finding and fixing memory leaks trivial.
  • A large, mature standard library providing prebuilt and pre-tested ways to accomplish common tasks without having to build your own, possibly buggy implementations.
  • Ships with useful tools, such as a powerful logging system and a profiler, to make tracking down problems easier.
  • Strong community support for common issues that aren't in the standard library, including a powerful third-party concurrency library.
share|improve this answer
    
I am a Delphi jockey from way back, but it went away from it's Pascal roots when it allowed me to typecast anything to anything else, a la C/C++: var I: Integer; Pointer(I)^ := $00; –  Jesse C. Slicer Dec 1 '10 at 14:36
1  
@Jesse: Perhaps, but I see that as a necessary concession to pragmatism. Kernighan made a lot of good points when he wrote Why Pascal is not my favorite programming language. Typecasts are necessary to get a lot of important low-level things done. But one of the strengths of Delphi is the way its libraries encapsulate low-level details and make most of the unsafe pointer and typecast stuff unnecessary. –  Mason Wheeler Dec 1 '10 at 15:27
    
I don't disagree that it may be necessary - but claiming Strong Typing is somewhat negated by this. Original Pascal didn't allow such shenanigans and therefore was strongly typed. But I wouldn't go so far to call Delphi weakly typed - it's sort of 'medium-well typed'. –  Jesse C. Slicer Dec 1 '10 at 15:29
1  
@Jesse: Didn't the original Wirth version of Pascal allow variant records? IIRC they eventually became so commonly used to subvert strong typing that Borland and others decided to just put typecasts in to make it simpler because everyone was doing it anyway. –  Mason Wheeler Dec 1 '10 at 15:38
    
en.wikipedia.org/wiki/Pascal_(programming_language)#Divisions and en.wikipedia.org/wiki/Pascal_(programming_language)#Criticism as well as pascal-central.com/ppl/chapter3.html seem to indicate it was part of the first standard in 1983. I do see some references by Wirth which seem to date to 1974, so I'd say yes it did. I think the problematic part was allowing it to be subverted as such (i.e.the variant fields taking the same memory, like unions in C). If they were simply used as a scoping mechanism and the memory layout were for the superset, it'd be stronger typed. –  Jesse C. Slicer Dec 1 '10 at 15:52
show 1 more comment

The less powerful a language is, the less options it gives you to shoot your own foot.

High-level languages like Java and C# will produce less bugs than low-level languages like C++.

Having said that I believe Java is more secure than C#. Java is artificially limited so that an average programmer without advanced knowledge can master it and produce stable programs.

share|improve this answer
3  
+1 for "The less powerful a language is, the less options it gibes you to shoot your own foot." –  Michael K Dec 1 '10 at 13:39
    
The chart from missingfaktor seems to say that C# and C++ are on equal "footing" as far as being able to shoot yourself there goes and elevates Java above that. Not that I agree with that part of the chart, though. You are forced to go through hoops to do some C# shooting. –  Jesse C. Slicer Dec 1 '10 at 14:32
1  
Safety and power are not inversely proportional (which is what you seem to think ;-) Haskell, for instance, is EXTREMELY powerful and yet has very few ways to shoot yourself in foot. –  missingfaktor Dec 1 '10 at 14:43
3  
If the language is weak, you just need a bigger foot. –  user1249 Dec 1 '10 at 18:23
5  
@missingfaktor, that is because it is a side effect to shoot yourself in the foot. –  user1249 Dec 1 '10 at 18:23
show 2 more comments

Since Excel is the most widely used DSL, I'll go with Excel. (excluding VBA of course)

It fits the bill:

  • It's always easy to reproduce (here's a spreadsheet - it's not working)
  • It's pretty easy to find the bug, as it's totally "functional" - start with the cell that's wrong and trace back all of its dependencies.
share|improve this answer
    
This might be true as long as you don't add up easy-to-find bugs. –  mouviciel Jan 22 '13 at 10:57
    
+1 A bit cheeky since Excel is data, not a language. Gave me a good laugh :) –  awashburn Apr 4 at 19:04
    
@awashburn - oh, I don't know. I think it qualifies as a language. Each cell is a "variable". Each variable is declaratively set as either a literal (such as 123 or ABC) or a function (=SUM(A2:A5)). Excel then evaluates all the variables, figuring out what order to solve dependencies, etc. It's certainly not just data. –  Scott Whitlock Apr 4 at 19:45
    
I retract my statement, it turns out that Excel is Turing Complete... I learned something wholly unsettling... –  awashburn Apr 4 at 20:26
add comment

Perhaps surveying the number of tools available for static and dynamic code analysis for every programming language could give an idea. The more tools for a language, it is more likely the language is either very popular among users or very popular in generating hard to find bugs. But I am unable to get Google point me to any study made on this subject. It should also be noted that some languages such as C can be used to work around the underlying hardware bugs as well as work around the wear and tear of the hardware as it ages.

share|improve this answer
1  
"work around the wear and tear of the hardware as it ages"...? –  j_random_hacker Dec 1 '10 at 13:20
    
I have read that some Unix OSes that run on mission critical machines check for the health of the CPU, RAM and such other hardware. serverfault.com/questions/56192/… discusses about this to some depth. If some lines in a RAM module become faulty over time, those faulty modules will not be used by the OS and it will not report them in the total physical memory available. Such things could be done on other hardware as well. –  vpit3833 Dec 1 '10 at 19:06
    
That's an interesting tidbit, but I don't see how it's relevant here. Also nothing in your link mentions these self-repairing Unix OSes -- it just talks about ways to stress-test a PC's hardware. –  j_random_hacker Dec 2 '10 at 6:22
1  
I mentioned it to mean that programs alone might not the sources of bugs, it could be the hardware or other external factors as well. –  vpit3833 Dec 2 '10 at 9:06
add comment

One thing to take into account is the turn around time.

For the last five years or so, I've mainly developed web applications in java (JSF, Seam, etc.). Recently I got a new job, and we're using Perl (with Catalyst and Moose).

I'm way more productive in Perl, than I was in Java.

Not needing to compile and (hot)deploy, is one reason. I also find that writing use cases is easier, as it can be done in a more iterative way. And the frameworks in Java seem to be unnecessary complex, at least for the projects I've been involved in.

I guess the number of bugs in my Perl code is more or less the same as the number of bugs in my Java code, it might even be higher. But, I find et easier and faster to find and fix these bugs.

share|improve this answer
add comment

Instead of talking about languages what about talking about language-features

  • java forces you to think about exceptions (throws ...) and you must either publisch or handle these exceptions. Does that realy prevent me from forgetting errorsituations or am i using more exceptions that are derived from SystemException that do not need this handling?
  • what about "design by contract" (http://en.wikipedia.org/wiki/Design_by_contract) that forces me to think about pre and postconditions. I have read that is now possible with c#-4.0.
share|improve this answer
add comment

This is a difficult question because most bugs aren't the fault of the language itself - rather they are the fault of developers making mistakes in how they use the language.

I believe there are several aspects of language features that affect the likelihood of bugs:

  • Interactivity - dynamic languages with REPLs encourage interaction / experimentation with running programs and much smaller code/test cycles. If you believe that iteration is a good way to discover clean simple solutions and detect/eliminate bugs then this would tend to favour interactive languages.

  • Expressiveness - if code is shorter and has less boilerplate / incidental complexity then it's easier to see bugs / logic errors.

  • Type safety - the more compile time checking, the more bugs will be caught by the compiler so in general type safety is a good thing. However these usually aren't hard to find bugs - even in a fully dynamic language the wrong type in a data structure will usually cause a very obvious runtime error, and TDD almost always picks up these kind of bugs.

  • Immutability - a lot of hard bugs are due to complex interactions of immutable state. Languages that emphasise immutability (Haskell, Clojure, Erlang) have an enormous advantage by eschewing mutability

  • Functional programming - functional approaches to writing code tend to be more "provably correct" than object oriented code with complex sequences of effects / interactions. My experience is that FP helps avoid tricky bugs - I believe there is some academic research somewhere that I can't currently find that backs this up.

  • Concurrency support - concurrency problems are particular hard to detect and debug which is why this is so important. Anything that requires manual locking is ultimately doomed to fail (and this includes pretty much every object oriented approach to concurrency). Best language I know of in this regard is Clojure - it has a unique approach to managing concurrency that combines software transactional memory with immutable data structures to get a novel, reliable and composable concurrency framework. See http://www.infoq.com/presentations/Value-Identity-State-Rich-Hickey for more insights

share|improve this answer
add comment

Not the answer you're looking for? Browse other questions tagged or ask your own question.