Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

All programming languages are having their design flaws simply because not a single language can be perfect, just as with most (all?) other things. That aside, which design fault in a programming language has annoyed you the most through your history as a programmer?

Note that if a language is "bad" just because it isn't designed for a specific thing isn't a design flaw, but a feature of design, so don't list such annoyances of languages. If a language is illsuited for what it is designed for, that is of course a flaw in the design. Implementation specific things and under the hood things do not count either.


locked by World Engineer Mar 31 '13 at 15:35

This question exists because it has historical significance, but it is not considered a good, on-topic question for this site, so please do not use it as evidence that you can ask similar questions here. This question and its answers are frozen and cannot be changed. More info: help center.

closed as not constructive by Mark Trapp Oct 7 '11 at 20:50

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.

Note that this is constructive for language designers (mistakes to avoid), if someone would like to question how constructive this question is. – Anto Mar 5 '11 at 16:08
@greyfade: Not really, this are about flaws in the actual language, that seems to be about things which lower adoption of a language, which could include bad standard library or just a bad website for the language. Some answers list e.g. bad syntax, but that isn't a specific design flaw – Anto Mar 5 '11 at 16:54
Greatest flaw in any programming language? Humans. – Joel Etherton Mar 7 '11 at 12:42

49 Answers 49

up vote 42 down vote accepted

One of my big annoyances is the way switch cases in C-derived languages default to falling through to the next case if you forget to use break. I understand that this is useful in very low level code (eg. Duff's Device), but it is usually inappropriate for application level code, and is a common source of coding errors.

I remember in about 1995 when I was reading about the details of Java for the first time, when I got to the part about the switch statement I was very disappointed that they had retained the default fall-through behaviour. This just makes switch into a glorified goto with another name.

@Christopher Mahan: switch doesn't have to work that way. For example, Ada's case/when statement (equivalent to switch/case) does not have fall-through behaviour. – Greg Hewgill Mar 5 '11 at 22:40
@Greg: switch-like statements in languages unrelated to C don't have to work that way. But if you use C-style control flow ({...}, for (i = 0; i < N; ++i), return, etc.), language inference will make people expect switch to work like C, and giving it Ada/Pascal/BASIC-like semantics would have confused people. C# requires break in switch statements for the same reason, although makes it less error-prone by forbidding silent fallthrough. (But I wish you could write fall; instead of the ugly goto case.) – dan04 Mar 6 '11 at 8:05
then don't write switch, write if() else. the reason you're complaining about is what makes switch better: it's not a true/false conditional, it's a numeral conditional, and that makes it different. You could also write your own switch function though. – jokoon Mar 6 '11 at 11:40
-1 I consider it a benefit to allow fall through, there is no danger from it other than stupidity, yet it grants additional function. – Orbling Mar 8 '11 at 0:25
The problem isn't that switch allows fallthrough. It's that most uses of fallthrough are not intentional. – dan04 Mar 8 '11 at 0:57

Probably not the greatest design flaw but a flaw nonetheless in my opinion...

The keyword final in the context of variables is Java.

I wish there was a non-final / mutable / rassignable keyword instead to indicate that the reference to a variable can be changed.

Good practices suggest that you should use the keyword final liberally in all cases especially when you are writing multi-threaded applications.

I follow this advice and use the final keyword whenever I can. It is very rare that I need a variable to be non-final. This makes my source code a lot more cluttered and forces me to type more than I really should have to.


The m4 macro language lacks a loop construct. Instead, the documentation recommends that you create your own using recursion. That kept me from bothering with the language, pretty much for ever.


Coldfusion's nested CFLoop behavior.



Its inventor, Tony Hoare, calls it the "billion dollar mistake".

It was introduced in ALGOL in the 60s, and exists in most of the commonly used programming languages today.

The better alternative, used in languages like OCaml and Haskell, is the maybe. The general idea is that object references cannot be null/empty/non-existent unless there's an explicit indication that they may be so.

(Although Tony's awesome in his modesty, I think almost anyone would have made the same mistake, and he just happened to be first.)

@user14579: Every language that supports any kind of set or string or array has {}, but such is still semantically appropriate and will not crash unless you already have something that could possibly cause an array bounds error -- but that's another issue. You can process an empty string to uppercase all the characters, which will result in an empty string. You try the same thing on a null string, and without proper consideration, it'll crash. The problem is that this proper consideration is tedious, often forgotten, and makes it difficult to write single-expression functions (i.e. lambdas). – Rei Miyasaka Mar 10 '11 at 20:15
I make money every time I type null...oh right someone loses money every time I type null. Except this time. – kevpie Mar 12 '11 at 12:59
@umlcat - when you have languages with pattern matching like Ocaml, Haskell, and F#, using the Maybe x | None pattern prevents you from forgetting the null case at compile-time. No amount of compile-time trickery can catch an error in languages where null is the established idiom. Since you have to explicitly choose not to deal with the null case in languages that have the Maybe and Some monad, they have a serious advantage over the "null" approach. – JasonTrue Mar 12 '11 at 22:27
@Jason -- I like to think of maybe as a null opt-in, whereas the null exception is an opt-out. Of course there's some things to be said about the difference between runtime errors and compile-time errors too, but just the fact that null is essentially injecting behavior is noteworthy in itself. – Rei Miyasaka Mar 13 '11 at 0:11

In C, and inherited by C++, Java, and C#:

You cannot parse the language without building a symbol table. Because code like this:

Foo Bar();

could be declaring a variable Bar of type Foo and calling the default constructor, or could be declaring a function Bar that returns a Foo and takes no arguments. (In C++, anyway. The others have similar flaws.)

This means you can't parse these languages without building a symbol table, making analysis tools much harder to write.

(Javascript and Go manage to avoid this problem.)


I have two things which I dislike in C++,

Implicit conversion to bool (this is made worse by the fact that you can implement conversion operators for types such as operator int() const {...})

Default parameters, yes it aids backward compatibility of interfaces when adding new stuff, but then so does overloading - so why do this?

Now combine the two together you have a recipe for disaster.


The worst sin of a programming language is not being well defined. A case I remember is C++, which, in its origins:

  1. Was so ill defined that you could not get a program to compile and run by following books or examples.
  2. Once you tweaked the program to compile and run under one compiler and OS, you'd have to start over if you switched compilers or platforms.

As I remember, it took about a decade to get C++ defined well enough as to make it as professionally dependable as C. It's something that should never happen again.

Something else I consider a sin (should it go in a different answer?) is having more than one "best" way to do some common task. It is the case of (again) C++, Perl, and Ruby.

I don't see how to avoid ill-definedness in an evolving language. Or, for that matter, in a predesigned language where the original designer missed some important points (like Pascal). – David Thornley Mar 11 '11 at 21:02

Cramming array, list and dictionary into one abomination called PHP's "associative arrays".

If you don't like this then you should probably avoid Lua as well. – finnw Nov 21 '11 at 3:00

I get the feeling that the people who designed PHP didn't use a normal keyboard, they don't even use a colemak keyboard, because they should have realized what they were doing.

I am a PHP developer. PHP isn't fun to type.

Who::in::their::right::mind::would::do::this()? The :: operator requires holding shift and then two key presses. What a waste of energy.

Although->this->is->not->much->better. That also requires three key presses with the shift being in between the two symbols.

$last = $we.$have.$the.$dumb.'$'.$character. The dollar sign is used a tremendous amount of times and requires the award stretch up to the very top of the keyboard plus a shift key press.

Why couldn't they design PHP to use keys that are much faster to type? Why couldn't or have vars start with a key that only requires a single keypress - or non at all (JavaScript) and just pre-define all vars (like I have to do for E_STRICT anyway)!

I'm no slow typist - but this is just a lame design choice.

So does C++, and for some inexplicable bizarre reason, PowerShell. – Rei Miyasaka Mar 9 '11 at 20:53
Use a more powerful editor, and define your own key sequences for those operators. – kevin cline Mar 9 '11 at 21:14
I::have::nothing::against::this->at.all() – Mateen Ulhaq Mar 12 '11 at 22:25
Maybe they don't use qwerty keyboards. $ and : don't need the shift key pressed on all the azerty like keyboards. – Arkh Oct 7 '11 at 15:55

Primitive types in Java.

They break the principle that everything is a descendant of java.lang.Object, which from a theoretical point of view leads to additional complexity of the language specification, and from a practical perspective they make the use of collections extremely tedious.

Autoboxing helped alleviate the practical drawbacks but at the cost of making the specification even more complicated and introducing a big fat banana skin: now you can get a null pointer exception from what looks like a simple arithmetic operation.


Although every language has it's faults, none are nuisances once you know about them. Except for this pair:

Complex syntax coupled with a wordy APIs

This is particularly true of a language like Objective-C. Not only is the syntax overwhelmingly complex but the API uses function names like:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

I'm all for being explicit and un-ambiguous, but this is ridiculous. Each time I sit down with xcode, I feel like a n00b, and that's really frustrating.


RoboCom, whose assembly language lack for bitwise operations.

While it hardly counts as any productive language with any real value other than learning and entertainment, RoboCom is a game where you are programming virtual robots to participate in a code battles. Programmers have to make most use of clock cycles to make their move before their opponent do.

If a language is illsuited for what it is designed for, that is of course a flaw in the design.

I found it quite irritating for a language to lack bitwise operations, especially when the goal of the game is elimination by optimization. That in my books, is a real design flaw, since many optimizations can be made using bitwise operations.

Wish I could have contributed something slightly more useful. :)


Optional paramaters in VB. When adding features to code is is too easy to do it as an optional parameter, then another, then another, so you end up with all these parameters that are only used in newer cases that were added after the initial code was written, and probably aren't called at all by older code.

Thankfully this was solved for me by switching to C# and using overloads.


The biggest flaw often seen in many programming languages is inability to 'bootstrap' - often it's not possible or practical to implement the language and its libraries using only that language itself.

When this is the case, language designers (and implementors) are skipping the hard part of making the language useful for really interesting and challenging tasks.

@DavidT DEFINITION COBOL. ARRAY OF CHARACTERS: {'C', 'O', 'B', 'O', 'L'}. (mostly-made-up syntax) – Mark C Mar 13 '11 at 20:18

In non-Java like languages. The concept of "GOTO" or Jumping. Being able to jump around the code in a non-linear way is perhaps the most ill-logical feature in any written language.

This has been the most misused and irrelevant concept. Once I see one of these in a 300 line function I know I'm in for a cooking lesson for spaghetti. The exception is error handling. This is the only acceptable use of the concept of jumping

It breaks good modern programming practices. Goto's are only acceptable for the purpose of error trapping. Not a lazy way to terminate loops or skip code.

Writing code is an art form that should is oriented for readability. Among many aspects for readability is linear execution. One entry point, one exit for any function, and it must flow down the page, no jumps or goto's.

Not only does this make the code more readable, it also by it's very nature helps you write higher quality code. One hack begets another and another. You'll generally find that once goto's are misued, you also get multiple exit statements out of functions. Tracing conditions and logic for testing becomes infinitely more difficult and immediately reduces the robustness of any code you may produce.

I wish Goto's would be banished forever, they were used in Assembly coding years ago, and that is where they should remain.

@SK-logic Generally speaking, would a GOTO be better replaced by a function call? – Mark C Mar 13 '11 at 16:06
@Mark C, no, of course not! See the state machine example - it will be severely obscured, and a potential for optimisation will be damaged. Also, it will make it even harder for higher level languages compilers to target a language that way. – SK-logic Mar 13 '11 at 16:49
@SK-logic Yes, but in the cases that GOTOs call reusable code, it is a function call with only slightly different syntax, right? I do not completely understand your example (FSM), but I understand intuitively that sometimes a lack of GOTOs could obscure program flow. I think you mean the case where the called block has GOTOs to other parts of the program. (Could you get equivalent functionality if function calls optionally did not return program control to the caller?) It seems GOTOs have two uses---function calls and control flow. – Mark C Mar 13 '11 at 20:12
@Mark C, in order to simulate goto behaviour with function calls, you'd have to translate the code into an SSA-form, then transform all the basic blocks into tiny functions with numerous parameters, each performing a tail-call of another basic block function. Firstly, it is a mess, and secondly, tail calls are not supported by many languages and runtimes. Actually, this transform is a great tool for reasoning about an imperative code with goto-s or any other control flow constructions (which should be lowered to goto first). – SK-logic Mar 13 '11 at 20:53
@SK-logic I want to say this without being critical of people: Not everyone has the same standard or background when they write programs. – Mark C Mar 14 '11 at 2:38

In old Ultima Online/sphere server scripting...there was no divide at all or decimal points, though the game itself obviously used them. You could make a somewhat crude divide function but just barely.

It is difficult to say how much of a train wreck that one flaw made the whole language extremely cumbersome.


Java, PHP, C#, Delphi, Vala: mixing "pointers to objects" versus "plain objects", what is usually called "references". In C++, and Object Pascal, you can create objects as static variables, and objects as dynamic variables, using pointer syntax.

Example (C++) :

x = new XClass();   
x->y = "something";
if (x == null) {

Example (Java / C#) :

x = new XClass();
x.y = "something";
if (x == null) {


When I learned COBOL, the ALTER statement was still a part of the standard. In a nutshell, this statement would allow you to modify procedure calls during runtime.

The danger was that you could put this statement in some obscure section of code that was rarely accessed and it had the potential to completely change the flow of the rest of your program. With multiple ALTER statements you could make it nearly impossible to know what your program was doing at any point in time.

My university instructor, very emphatically, stated that if he ever saw that statement in any of our programs he would automatically flunk us.


I think all the answers so far point to a single failing of many mainstream languages:

There is no way to change the core language without affecting backward compatibility.

If this is solved then pretty much all those other gripes can be solved.


this can be solved in libraries by having different namespaces, and you could conceive of doing something similar for most of the core of a language, though this might then mean you need to support multiple compilers/interpreters.

Ultimately I don't think I know how to solve it in a way that is totally satisfactory, but that doesn't mean a solution doesn't exist, or that more can't be done

How would you go about "solving" this? – Bjarke Freund-Hansen Mar 9 '11 at 18:36
By backwards compatible, do you mean newer compilers should be able to compile old code? – Rei Miyasaka Mar 10 '11 at 1:08

Javascript's omission of many of the date formatting and manipulation functions that almost every other language (including most SQL implementations) have has been a source of frustration for me recently.


I feel like I'm opening myself up to get flamed, but I really hate the ability to pass plain old data types by reference in C++. I only slightly hate being able to pass complex types by reference. If I'm looking at a function:

void foo()
    int a = 8;

From the calling point, there is no way to tell that bar, which may be defined in a completely different file, is:

void bar(int& a)

Some might argue that doing something like this may just be a bad software design, and not to blame the language, but I don't like that the language lets you do this in the first place. Using a pointer and calling


is much more readable.

@Jeff: For one thing, the primary reason that reference semantics made their way into C++ was operator overloading, for which uniform reference behaviour simply makes sense. More importantly, though, C++ is designed to be versatile and provide very fine-grained features, even if doing so incurs significant risk of programmer error. So yeah, at least in this particular case, don't blame the language. I'd rather be able to make mistakes than let a language get in my way. – Jon Purdy Mar 10 '11 at 4:47

Statements, in every language that has them. They do nothing that you can't do with expressions and prevent you from doing lots of things. The existence of a ?: ternary operator is just one example of having to try to get around them. In JavaScript, they are particularly annoying:

// With statements:
node.listen(function(arg) {
  var result;
  if (arg) {
    result = 'yes';
  } else {
    result = 'no';
  return result;

// Without:
node.listen(function(arg) if (arg) 'yes' else 'no')
Correct. Expressions for everything. – munificent Mar 8 '11 at 6:11
Lisp works well for this. – David Thornley Mar 8 '11 at 15:50
@SK-logic: I suspect that statements were blindly inherited from machine language, through FORTRAN, ALGOL, and COBOL. – David Thornley Mar 8 '11 at 21:15
I'm pretty sure machine language is the common ancestor, and that's just a reflection of the fact that modern computers based on von Neumann architecture execute instructions sequentially and modify state. Ultimately when IO happens, there are going to be expressions that don't yield meaningful data, so statements aren't entirely useless in indicating semantically that some code has only side effects. Even languages that have a notion of unit type (aka ()) instead of statements have special consideration to ensure that they don't throw warnings or otherwise behave strangely. – Rei Miyasaka Mar 9 '11 at 21:03

Perl's flattening of lists... Conversely, it's also one of it's best features.


Delphi / Pascal language don't allow multiline strings without using concatenation.


Lack of array handling for input variables in SQL. Even when a database vendor has added on a feature to support this (I'm looking at you, SQL Server), it can be poorly designed and awkward to use.


I'm going to go back to FORTRAN and whitespace insensitivity.

It pervaded the specification. The END card had to be defined as a card with an 'E', an 'N', and a 'D' in that order in columns 7-72, and no other nonblanks, rather than a card with "END" in the proper columns and nothing else.

It led to easy syntactic confusion. DO 100 I = 1, 10 was a loop control statement, while DO 100 I = 1. 10 was a statement that assigned the value 1.1 to a variable called DO10I. (The fact that variables could be created without declaration, their type depending on their first letter, contributed to this.) Unlike other languages, there was no way to use spaces to separate out tokens to allow disambiguation.

It also allowed other people to write really confusing code. There's reasons why this feature of FORTRAN was never duplicated ever again.

In a language where you can redefine literals that's the worst example - I mean it only caused one tiny little spacecraft to crash – Martin Beckett Mar 8 '11 at 0:10
@Martin Beckett - redefining literals in FORTRAN was really a compiler flaw rather than a language feature. It certainly wasn't an intentional language feature. – Stephen C Mar 10 '11 at 1:56
@oosterwal: I certainly did. I might be wrong, but I vaguely remember the language definition based on punch cards. They were the main way of inputting FORTRAN programs back then, and the idea of an 80-column line with columns 73-80 reserved is from punch cards. – David Thornley Mar 10 '11 at 14:30

The decision to implement the goto operator in PHP 5.3.
What reason could there possibly be to encourage bad programming practices that were -wisely- not implemented in previous versions?

Overzealous goto bashing amuses me. It is not a bad programming practice, it is an essential form of control flow. PHP code is often generated rather than hand-written, and for a compilation target language goto is a must-have. – SK-logic Mar 7 '11 at 11:56
goto is only essential in languages that lack exceptions, and very essential in languages that lack while, else, switch, etc. (like old line-numbered BASIC). – dan04 Mar 7 '11 at 14:45
@dan04, exceptions are not a substitute for a goto. Think of implementing a state machine efficiently with no goto. And it is quite a common pattern when compiling from some higher level language. Many other thigs are also much easier to compile if your target language provides a proper goto, and can be a hell if only a structural control flow is available. – SK-logic Mar 7 '11 at 15:07

One could list hundreds of mistakes in hundreds of language, but IMO it is not a useful exercise from a language design perspective.


Because something that would be a mistake in one language would not be a mistake in another language. For instance:

  • Making C a managed (i.e. garbage collected) language or tying down the primitive types would limit its usefulness as a semi-portable low-level language.
  • Adding C-style memory management to Java (for example, to address performance concerns) would break it.

There are lessons to be learned, but the lessons are rarely clear cut, and to understand them you have to understand the technical trade-offs ... and the historical context. (For instance, the cumbersome Java implementation of generics is a consequence of an overriding business requirement to maintain backwards compatibility.)

IMO, if you are serious about designing a new language, you need to actually use a wide range of existing languages (and study historical languages) ... and make up your own mind what the mistakes are. And you need to bear in mind that each of these languages was designed in a particular historical context, to fill a particular need.

If there are general lessons to be learned they are at the "meta" level:

  • You cannot design a programming language that is ideal for all purposes.
  • You cannot avoid making mistakes ... especially when viewed from hind-sight.
  • Many mistakes are painful to correct ... for users of your language.
  • You have to take account of the background and skills of your target audience; i.e. existing programmers.
  • You cannot please everyone.
-1 -- programming languages follow design goals. A features of a language that work against these goals is a design flaws, unless it is a necessary compromise for one of its other goals. Not many languages are made with the intention of satisfying everyone, but all languages should attempt to satisfy those people that it sets out to satisfy in the first place. This kind of postmodernistic political correctness is quite stifling to programming language research and development. – Rei Miyasaka Mar 9 '11 at 22:08
seems to me that the OP already accounted for your answer in the second paragraph of the question. – Aidan Cully Mar 10 '11 at 9:14

The preprocessor in C and C++ is a massive kludge, creates abstractions that leak like sieves, encourages spaghetti code via rat's nests of #ifdef statements, and requires horribly unreadable ALL_CAPS names to work around its limitations. The root of these problems is that it operates at the textual level rather than the syntactic or semantic level. It should have been replaced with real language features for its various use cases. Here are some examples, though admittedly some of these are solved in C++, C99 or unofficial but de facto standard extensions:

  • #include should have been replaced with a real module system.

  • Inline functions and templates/generics could replace most of the function call use cases.

  • Some kind of manifest/compile time constant feature could be used for declaring such constants. D's extensions of enum work great here.

  • Real syntax tree level macros could solve a lot of miscellaneous use cases.

  • String mixins could be used for the code injection use case.

  • static if or version statements could be used for conditional compilation.

@dsimcha: I agree with the #include issue, but the module system was invented... afterward! And C and C++ aim for a maximum of backward compatibility :/ – Matthieu M. Mar 6 '11 at 13:34
I agree that this is a massive pain in various body parts, but the multi-pass design has the advantage of simplicity: a C compiler doesn't need to know much about the context of operation before it can successfully compile a chunk of C code. This can only be qualified as a design error if you can show that the costs of using a hypothetical module system within the C language itself (e.g. C++-like classes) is always lower than or comparable to the present cpp-based #include hacking. – reinierpost Mar 8 '11 at 9:00
@Stephen: I agree that Java with a preprocessor might be better than Java without, but only because Java doesn't have several of the "real" features necessary to replace the preprocessor. In languages like D, which include such features and Python, which gets flexibility in other ways by being dynamic, I don't miss it one bit. – dsimcha Mar 10 '11 at 3:55

protected by Adam Lear Mar 8 '11 at 3:28

Thank you for your interest in this question. Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

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