YourLanguageSucks
From TheoryOrg
JavaScript sucks because:
Poor Design
- Every script is executed in a single global namespace that is accessible in browsers with the window object.
- Camel case sucks:
XMLHttpRequest HTMLHRElement
- Automatic type conversion between strings and numbers, combined with '+' overloaded to mean concatenation and addition. This creates very counterintuitive effects if you accidentally convert a number to a string:
var i = 1; // some code i = i + ""; // oops! // some more code i + 1; // evaluates to the String '11' i - 1; // evaluates to the Number 0
- The automatic type conversion of the + function also leads to the intuitive effect that += 1 is different then the ++ operator:
var j = "1"; j++; // j becomes 2 var k = "1"; k += 1; // k becomes "11"
- The var statement uses function scope rather than block scope, which is a completely unintuitive behavior. You may want to use let instead.
Type System
- JavaScript puts the world into a neat prototype hierarchy with Object at the top. In reality values do not fit into a neat hierarchy.
- It is costly to navigate through __proto__, so prototypal inheritance is problematic.
- You can't inherit from Array or other builtin objects very easily. The syntax for prototypal inheritance also tends to be very cryptic and unusual.
- In JavaScript, prototype-based inheritance sucks: functions set in the prototype cannot access arguments and local variables in the constructor, which means that those "public methods" cannot access "private fields". There is little or no reason for a function to be a method if it can't access private fields.
- JavaScript doesn't support hashes or dictionaries. You can treat objects like them, however, Objects inherit properties from __proto__ which causes problems.
- JavaScript doesn't have real arrays. Instead JavaScript just has objects.
typeof [1, 2, 3, 4, 5] === "object"
- Arguments is not an Array. You can convert it to one with slice:
var args = Array.prototype.slice.call(arguments);
- The number type has precision problems.
0.1 + 0.2 === 0.30000000000000004;
(However, the problem is not the result, which is expected, but the choice of using floating point number to represent numbers, and this is a lazy language designer choice. See http://www.math.umd.edu/~jkolesar/mait613/floating_point_math.pdf ).
- NaN stands for not a number, yet it is a number.
typeof NaN === "number" // To make matters worse NaN doesn't equal itself NaN != NaN NaN !== NaN // This checks if x is NaN x !== x
(Which is as it should be, as per IEEE754. Again, the problem is the indiscriminate choice of IEEE754 by the language designer or implementor.)
Bad Features
(You can bypass many of these bad features by using http://www.jslint.com/)
- JavaScript inherits many bad features from C, including switch fallthrough, the use of = for both assignment and equality, and the position sensitive ++ and -- operators. See C sucks below.
- JavaScript inherits a cryptic and problematic regular expression syntax from Perl.
- Semi colon insertion
// This doesn't work properly
return
{
"a": 5
};
- Implied globals:
// Oops I left off the var keyword, now I have a global variable foo = 5;
- The == operator sucks
0 == "" 0 == "0" 0 == " \t\r\n " "0" == false null == undefined "" != "0" false != "false" false != undefined false != null
- The bitwise operators (& | ^ ~ << >> >>>) are inefficient because they convert their operands to floating point and then back.
- Typed wrappers suck:
new Function("x", "y", "return x + y");
new Array(1, 2, 3, 4, 5);
new Object({"a": 5});
new Boolean(true);
- parseInt has a really weird default behavior so you are generally forced into adding that you want your radix to be 10:
parseInt("72", 10);
- The with statement sucks because it is error-prone.
with (obj) {
foo = 1;
bar = 2;
}
- The for in statement loops through members inherited through the prototype chain, so you generally have to wrap it in a long call to object.hasOwnProperty(name).
for (var name in object) {
if (object.hasOwnProperty(name)) {
/* ... */
}
}
- There aren't numeric arrays, only objects with properties, and those properties are named with text strings; as a consequence, the for-in loop sucks when done on pseudo-numeric arrays because the iterating variable is actually a string, not a number (this makes integer additions difficult as you have to manually
parseIntthe iterating variable at each iteration).
var n = 0;
for (var i in [3, 'hello world', false, 1.5]) {
i = parseInt(i); // output is wrong without this cumbersome line
alert(i + n);
}
- There are also many deprecated features (see https://developer.mozilla.org/en/JavaScript/Reference/Deprecated_Features) such as getYear and setYear on Date objects.
Missing Features
- There should be some means of enforcing immutability. Your best bet is the const statement which is non-standard, non-cross browser, and specific to Mozilla. This statement, also doesn't work for JavaScript's most important datatype: objects.
// It works okay for numbers and strings
const pi = 3.14159265358;
const msg = "Hello World";
// It doesn't work for objects
const bar = {"a": 5, "b": 6};
const foo = [1, 2, 3, 4, 5];
// You also can't easily make your parameters constant
const func = function() {
const x = arguments[0], y = arguments[1];
return x + y;
};
- There should be a more convenient means of writing functions that includes implicit return, especially when you are using functional programming features such as map, filter, and reduce.
// JavaScript 1.8 introduces a somewhat nicer function syntax with implicit return: function(x) x * x
- There is still no particularly good means of looping, so you continue to see staments like these:
for (var i = 0, l = arr.length; i < l; i++) {}
- You still have to manually perform type checking:
function substr(str, start, end) {
if (arguments.length !== 3) {
throw new Error();
}
if (typeof str !== "string" || typeof start !== "number" || typeof end !== "number") {
throw new TypeError();
}
}
- Considering the importance of exponentiation in mathematics, Math.pow should really be an infix operator such as ** rather than a function.
Math.pow(7, 2); // 49
- no Math.sign or Math.signum function.
DOM
- Browser incompatibilities between Firefox, Internet Explorer, Opera, Google Chrome, Safari, Konqueror, etc make dealing with the DOM a pain.
- If you have an event handler that calls alert(), it always cancels the event, regardless of whether you want to cancel the event or not
// This event handler lets the event propagate
function doNothingWithEvent(event) {
return true;
}
// This event handler cancels propagation
function doNothingWithEvent(event) {
alert('screwing everything up');
return true;
}
PHP sucks because:
-
'0',0, and0.0are false, but'0.0'is true -
__toString()on PHP 5 objects only gets called forprint()andecho(), not concatenating or casting - There is no one consistent idea of what an expression is. There are at least three: normal, plus the following exceptions:
- here doc syntax
"<<<END"can not be used in the initiation of method attribute default values on PHP < 5.3
- here doc syntax
- The documentation is not versioned. There is a single version of the docs that you are supposed to use for php4.x, php5, php5.1...
- There is no general concept of an identifier. Some identifiers (like variable names) are case sensitive, others case insensitive (like function calls):
$x = Array(); $y = array(); $x == $y; # is true $x = 1; $X = 1; $x == $X; # is false
- If a function returns an Array, you just can not write (in PHP < 5.4) -
$first_element = function_returns_array()[0]; //Syntax ERROR!! $first_element = ( function_returns_array() )[0]; //This neither!! //Instead you must write $a = function_returns_array(); $first_element = $a[0];
- if you mis-type the name of a built-in constant, no error is raised; instead, it is interpreted as a string "nonexistent_constant_name"
- if you send too much arguments to a user-defined function call, no error is raised; the extra arguments are ignored
- if you send the wrong number of arguments to a built-in function call, an error is raised; the extra arguments aren't ignored such as with a normal function call
-
Array()is a hash & array in one data type - fatal errors do not include a traceback or stack trace
- it doesn't have dynamic scoping
- it has identifier auto-vivification with no equivalent of
"use strict" - in addition to implementing POSIX STRFTIME(3), roll-your-own date formatting language.
- order of parameters to mktime is totally random: mktime(hour, minute, second, month, day, year)
- Numbers beginning with
0are octals, so08,09,012345678and the like should raise an error. Instead, it just ignores any digits after the first 8 or 9:08 == 0,08 != 8,0777 == 07778123456. - weakass string interpolation resolver:
error_log("Frobulating $net->ipv4->ip");
Frobulating Object id #5->ip
$foo = $net->ipv4;
error_log("Frobulating $foo->ip");
Frobulating 192.168.1.1
- there are two ways for end-of-line comments: // and #
- code must always be inserted between
<?phpand?>tags, even if it's not HTML generation code disputed on discussion page - two names for the same floating point type:
floatanddouble - there are pseudo-types to define parameters that accept multiple types, but no way to set a type for a specific parameter other than for objects or arrays (or callables since PHP 5.4)
- an integer operation overflow automatically converts the type to float
- There are thousands of functions. If you have to deal with arrays, strings, databases, etc., you'll get with tens of functions such as
array_diff,array_reverse, etc. Operators are inconsistent; you can only merge arrays with +, for example (- doesn't work). Methods? No way:$a.diff($b), $a.reverse()don't exist. - function names aren't homogeneous:
array_reverseandshuffleboth operates on arrays - string characters can be accessed through both brackets and curly brackets
- variable variables introduce ambiguities with arrays:
$$a[1]must be resolved as${$a[1]}or${$a}[1]if you want to use$a[1]or$aaas the variable to reference to. - constants can only be defined for scalar values (booleans, integers, resources, floats and strings)
- constants do not use
$prefix, like variables -
!has a greater precedence over=but... not in thisif (!$a = foo())"special" case! - on 32 and 64 bit systems shift operators (
<< >> <<= >>=) have different results for more than 32 shifts - (instances of) built-in classes can be compared, but not user-defined ones
- arrays can be "uncomparable"
-
andandoroperators do the same work of&&and||, but just with different precedence - there's no integer division, just floating point one, even if both operands are integers; you must truncate the result to have back an integer
- there are both curly brackets and
:followed byendif;,endwhile;,endfor;, orendforeachto delimit blocks for the respective statements -
++and--cannot be applied to booleans - there are both
(int)and(integer)to cast to integers,(bool)and(boolean)to cast to booleans, and(float),(double), and(real)to cast to floats - casting from float to integer can lead to undefined results if the float is beyond the boundaries of integer
- using
[]or{}to a variable whose type is not an array or string gives backNULL - included file inherits the variable scope of the line on which the include occurs, but functions and classes defined in the included file have global scope
- if an included file must return a value but the file cannot be included,
includestatement returnsFALSEand only generates a warning - functions and classes defined into other functions or classes have global scope: they can be called outside the original scope
- defaults in functions should be on the right side of any non-default arguments, but you can define them everywhere leading to unexpected behaviours:
function makeyogurt($type = "acidophilus", $flavour)
{
return "Making a bowl of $type $flavour.\n";
}
echo makeyogurt("raspberry"); // prints "Making a bowl of raspberry ". Only a warning will be generated
- methods can be called both as instance methods (with
$thisspecial variabile defined) and class methods (withself) - (PHP 4) a method defined in a base can "magically" become a constructor for another class if its name matches the class one:
class A
{
function A()
{
echo "Constructor of A\n";
}
function B()
{
echo "Regular function for class A, but constructor for B";
}
}
class B extends A
{
}
$b = new B; // call B() as a constructor
- (PHP 4) there are constructors but not destructors
- (PHP 4) there are "class methods" but not class variables
- if the class of an object which must be unserializing isn't defined when calling
unserialize(), an instance of__PHP_Incomplete_Classwill be created instead, loosing any reference to the original class - (PHP 4) references in constructors doesn't work:
class Foo {
function Foo($name) {
// create a reference inside the global array $globalref
global $globalref;
$globalref[] = &$this;
$this->setName($name);
}
function echoName() {
echo "\n", $this->name;
}
function setName($name) {
$this->name = $name;
}
}
$bar1 = new Foo('set in constructor');
$bar1->setName('set from outside');
$bar1->echoName(); // prints "set from outside"
$globalref[0]->echoName(); // prints "set in constructor"
// It's necessary to reference the value returned from new to have back a reference to the same object:
$bar2 =& new Foo('set in constructor');
$bar2->setName('set from outside');
$bar2->echoName(); // prints "set from outside"
$globalref[1]->echoName(); // prints "set from outside"
- exceptions in the __autoload function cannot be catched, leading to a fatal error (PHP < 5.3)
- foreach applied to an object iterates through its variables by default
- static references to the current class like self:: or __CLASS__ are resolved using the class in which the function are defined (solvable in PHP >= 5.3 with static::):
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test(); // prints A, not B!
- nested class (class in class) are not supported
class a {
function nextFoo() {
class b {} //not supported
}
}
- globals aren't always "globals":
$var1 = "Example variable";
$var2 = "";
function global_references($use_globals)
{
global $var1, $var2;
if (!$use_globals) {
$var2 =& $var1; // visible only inside the function
} else {
$GLOBALS["var2"] =& $var1; // visible also in global context
}
}
global_references(false);
echo "var2 is set to '$var2'\n"; // var2 is set to
global_references(true);
echo "var2 is set to '$var2'\n"; // var2 is set to 'Example variable'
- there's no module / package concept: only include files, "ala C"
- no way to store 64-bit integers in a native data type on a 32-bit machine, leading to inconsistencies (intval('9999999999') returns 9999999999 on a 64-bit machine, but returns 2147483647 on a 32-bit machine)
- (PHP < 5.3) no support for closures; create_function does not count since it takes a string as the argument and doesn't reference the scope it was created in
Perl 5 sucks because:
- Perl is worse than Python because people wanted it worse. Larry Wall, 14 Oct 1998
- use strict -- really, it should be 'use unstrict' or 'use slop' (as in billiards/pool) that changes things, and that itself should never ever be used. Ever. By anyone. 'strict' mode should be the default.
use strict; use warnings;
- Sigil variance is hugely annoying
my @list = ("a", "b", "c");
print $list[0];
- no parameter lists (unless you use Perl6::Subs)
sub foo {
my ($a, $b) = @_;
}
- dot-notation for methods, properties, etc is a good thing, especially when so many other C-styled languages do it and Perl is one of the random ones that doesn't.
- The type system should be revamped. There is only support for (Scalar, Array, Hash, etc) and not support for (Int, Str, Bool, etc).
- It is too hard to determine the type of a Scalar, e.g there is no easy way to determine if a variable is a string.
- Just try explaining a ref to a C programmer. They will say "oh, it's a pointer!" except it isn't. Not really. It's like a pointer, or so I hear. As a Perl programmer, I know that it's not quite a pointer, but I don't know exactly what a pointer is (while I do know what a ref is, but I can't explain it -- neither could Larry Wall: He called it a 'thingy').
- The regular expression syntax is horrid.
- there's rarely a good place to put the semicolon after a here-doc.
my $doc = <<"HERE"; But why would you? HERE print $doc;
- hashes don't stay in order like they do in most other languages. This can (and, except for luck, does) mean that reading a JSON string into a data structure and then reencoding it without modifying it except to decode and encode will end up with a different JSON string (even without paying attention to anything that might otherwise muck it up like different character encoding schemes or differences in whitespace used by the encoder).
- it generally takes you ten years to figure out how to call functions or methods inside double-quoted strings like any other variable. If you're reading this, though, you get a break: "You do it @{[sub{'like'}]} this. Easy"
- just like Ruby it has redundant keyword "unless". You can do "if not" at least in three ways:
1) if(!expression) 2) if(not expression) 3) unless(expression) It could lead to confusion and spoiling readability of code.
Python sucks because:
- mandatory self argument in methods
- The syntax for singleton tuples,
(x,), is confusing, and different from the syntax for singleton lists:
(1) == 1 # (1) is just 1 [1] != 1 # [1] is a singleton list (1,) != 1 # (1,) is a singleton tuple (1) + (2) != (1,2) # (1) + (2) is 1 + 2 = 3 [1] + [2] == [1,2] # [1] + [2] is a two-element list (1,) + (2,) == (1,2) (1, + 2,) == (1,2) # 1, is the same as (1,) (1,2) + (3,4) == (1,2,3,4)
- default values for optional, key-word arguments are evaluated at parse-time, not call-time Note: You could use decorators to simulate dynamic default arguments
- No labeled break or continue
- the body of lambda functions can only be an expression, no statements; this means you can't do assignments or print inside a lambda, which makes them pretty useless - in python 3, print is a function
- no switch statement -- you have to use a bunch of ugly if/elif/elif ... tests, or ugly dispatch dictionaries (which have inferior power).
- as a dynamic language, there's no convenient way to statically check for misspelled variable names
- from python docs:
!=can also be written<>(see php). unified in Python 3 - no assignment in while condition
- the syntax for conditional-as-expression is awkward in Python (x if cond else y). Compare to C-like languages: (cond ? x : y)
- no tail-call optimization, ruining the efficiency of some functional programming patterns
- as is typical of major revision updates, there are breaking changes between Python 2.x and 3.x
- incomplete native support for complex numbers: both
(-1)**(0.5)andpow(-1, 0.5)raise an error instead of returning0+1j. - no constants
- local variables are implicitly declared on assignment. This means in order to change global variables or variables in the closure you need to declare those using
globalandnonlocalin the function in which you change them. (nonlocalis Python 3 only) If variables would be need to be declared similar as in JavaScript you would not need this.
Ruby sucks because:
-
String#downcase? Who calls it "downcase?" It's called "lower case," and the method should be called "lowercase" or "lower". AndString#upcaseshould have been called "uppercase" or "upper". - Unicode support should have been built in from 1.0, not added after much complaining in 1.9/2.0 in 2007
- No support for negative / positive look-behind in regular expressions in 1.8
- Regular expressions are always in multi-line mode
- No real support for arbitrary keyword arguments (key=value pairs in function definitions are positional arguments with default values)
- The documentation is not versioned.
- Using
@and@@to access instance and class members can be unclear at a glance. - There are no smart and carefully planned changes that can't break compatibility; even minor releases can break compatibility: See "Compatibility issues" and "fileutils". This leads to multiple recommended stable versions: both 1.8.7 and 1.9.1 for Windows. Which one to use?
- Experimental and (known to be) buggy features are added to the production and "stable" releases: See "passing a block to a Proc".
- The documentation is unchecked: it has dead links, like Things Any Newcomer Should Know
- The documentation is not up to date: Ruby C API Reference refers to version 1.8.4, but the latest stable release is 1.8.7.
- There's some minor gotchas.
nil.to_iturns nil into 0, but 0 does not evaluate as nil.nil.to_i.nil? #=> false -
String#to_ijust ignores trailing characters, meaning:"x".to_i == 0 - Ruby allows users to modify the built in classes, which can be useful, but limited namespace means addons can conflict. Experienced programmers know to add functionality through modules rather than monkey patching the built in classes, but is still prone to abuse. This has been promised to be resolved in ruby 2.0
- Aliased methods in the standard library make reading code written by others more confusing. E.g.
Array#size/Array#length,Array#[]/Array#slice - Mutable strings in a dynamic language! This means e.g. when a string is passed to a setter it should copy the string so the object can be sure that it won't change unexpectedly.
- Mutable types like arrays are still hashable. This can cause a hash to contain the same key twice, and return a random value (the first?) when accessing the key.
- Omitting parenthesis in function calls enable you to implement/simulate property setter, but can lead to ambiguities.
- Minor ambiguities between the hash syntax and blocks (closures), when using curly braces for both.
- Redundant operators:
||/or,&&/and,!/not. - Suffix-conditions after whole blocks of code, e.g.
begin ... rescue ... end if exprYou are guaranteed to miss theif exprif there are a lot of lines in the code block. - The
unlesskeyword (=if not) tends to make the code harder to comprehend instead of easier. - Difference between unqualified method calls and access of local variables is not obvious. This is especially bad in a language that does not require you to declare local variables and where you can access them without error before you first assign them.
- "Value-leaking" functions. The value of the last expression in an function is implicitly the return value. You need to explicitly write
nilif you want to make your function "void" (a procedure). - pre-1.9: No way to get stdout, stderr and the exit code (all of them at once) of a sub process.
-
``syntax with string interpolation for running sub processes. This makes shell injection attacks easy. - Regular expressions magically assign variables:
$1,$2, ... - Standard containers (
Array,Hash) have a very big interfaces that make them hard to emulate. - Symbols and strings are both allowed and often used as keys in hashes, but
"foo" != :foo, which led to inventions likeHashWithIndifferentAccess. - Parser errors could be more clear. "syntax error, unexpected kEND, expecting $end" actually means "syntax error, unexpected keyword 'end', expecting end of input"
Flex/ActionScript sucks because:
- The String class is defined as final, so if you want to add a function to the woefully incomplete String class, like startsWith or hashCode, you have to implement pass thrus for all the String methods.
- Method variables are scoped to the whole method, not to the current code block. (Note that this also sucks in JavaScript)
Scripting languages suck because:
- They are too domain specific, so when you want to go out of your domain you have to use some other scripting language, and when you want to extend the language itself or doing anything really advanced you have to use a systems language. This leads to a big mess of different programming languages.
C sucks because:
- Manual memory management can get tiring.
- String handling is manual memory management. See above.
- The support for concurrent programming is anemic.
- Terribly named standard functions: isalnum, fprintf, fscanf, etc.
- The preprocessor.
- Switch fallthrough will get you.
- Not feeling your smartest today? Have a segfault.
- If that code is legacy, you're in for two days of not looking like a hero.
C++ sucks because:
Some points in this section have been disputed on the discussion page.
- It is backward compatible with C.
- Still with subtle differences that make some C code unable to compile in a C++ compiler.
- The standard libraries offer very poor functionalities compared to other languages' runtimes and frameworks.
- C++ doesn't enforce a single paradigm. Neither procedural nor object-oriented paradigms are enforced, resulting in unnecessary complication. [Some people consider this as an advantage.]
- Too hard to implement and to learn: the specification has grown to over 1000 pages.
- Not suitable for low level system development and quickly becomes a mess for user level applications.
- The standard has no implementation for exception handling and name mangling. This makes cross-compiler object code incompatible.
- No widely used OS supports the C++ ABI for syscalls.
- What is 's', a function or a variable? (Answer: it's actually a function; for a variable, you have to omit the parentheses; but this is confusing since you use usually the parentheses to pass arguments to the constructor.)
std::string s();
- There is try but no finally
- No native Unicode support. You just can't write international and portable programs.
- No native thread support: you can't even write portable multithreaded programs!
- Operators can be overloaded only if there's at least one class parameter.
- This also makes impossible concatenating character array strings, sometimes leading programmers to use horrible C functions such as
strcat.
- This also makes impossible concatenating character array strings, sometimes leading programmers to use horrible C functions such as
-
catch (...)doesn't allow to know the type of exception. -
throwin function signatures is perfectly useless. - The exception system is not integrated with the platform: dereferencing a
NULLpointer will not throw a C++ exception. -
mutableis hard to use reasonably and, since it fucks upconstand thus thread safety, it can easily bring to subtle concurrency bugs. - The standard committee is unable to establish a memory model and thus add multithreading support, lol.
- Declaring a local static variable brings to undefined behavior in multithreaded programs: the variable can be either allocated per-thread (in thread local storage) or per-program (in global data segment); most compilers implement the second choice, but the standard doesn't talk about multithreading or multitasking at all.
- Closures have to be expressed explicitly in lambda expressions (never heard about anything like that in any functional language).
- You can use
[=]and enclose everything, but that still adds verbosity.
- You can use
- Lambdas have unique types that cannot be expressed and that makes them very hard to use. For example, standard functions cannot return lambdas.
- The nature of C++ has led developers to write compiler dependent code, creating incompatibility between different compilers and even different versions of the same compiler.
- An
std::string::c_str()call is required to convert anstd::stringto achar*. From the most powerful language ever we would have all appreciated a damn overloadedoperator const char* () const. - Developers have to worry about optimization matters such as whether declaring a function
inlineor not; and, once they've decided to do it, it is only a suggestion: the compiler may decide that was an incorrect suggestion and not follow it. What's the point? Shouldn't developers worry about optimization matters?- To rectify this nonsense many compilers implement
__forceinlineor similar.
- To rectify this nonsense many compilers implement
- Templates are Turing-complete, hence compilers have to solve the halting problem (undecidable) to figure out whether a code will even compile.
- Unused global symbols do not generate any warnings or errors, they are compiled and simply increase the size of the generated object file.
C# sucks because:
This section is only a stub. You can contribute by subscribing and expanding it.
- Supports 'goto'.
- Two distinct sets of collections: non-generic and generic. Stack and Queue have the same name in both their generic and non-generic flavors, but then we have Hashtable (non-generic) and Dictionary (generic).
- SortedList uses key-value pairs. There is no standard .NET collection for a list that keeps its items in sort order.
- HashSet was not introduced until .NET 3.5, even though it had been around in Java for some time.
- Parameters are not supported for most properties, only indexers, even though this is possible in Visual Basic .NET.
Java sucks because:
Some points in this section have been disputed on the discussion page.
- Overly verbose.
- No first class functions.
- Exceptions as part of the type system means you have to catch every imaginable exception that might be thrown, unless it is unchecked. It has been shown that this reduces productivity.
- Functions in the standard library do not use consistent naming, acronym and capitalization conventions, making it hard to remember exactly what the items are called:
-
java.nethasURLConnectionandHttpURLConnection: why notUrlConnectionorHTTPURLConnectionorHttpUrlConnection? -
java.utilhasZipOutputBufferandGZIPOutputBuffer: why notZIPOutputBufferorGnuZipOutputBufferorGzipOutputBufferorGZipOutputBuffer?
-
- Nearly everything is wrapped with objects and many things must be buffered, even those things that don't really need to be objects or be buffered.
- There's
inttypes andIntegerobjects,floattypes andFloatobjects. So you can have efficient data types, or object-oriented data types. Wouldn't it be better to make your object-oriented types efficient? - Java has unused keywords, such as
gotoandconst. - Interface method implementations are necessarily public, preventing to make an interface implementation accessible only to subclasses and same package classes.
- You can't inherit a class as protected or private, your classes must publicly show everything they inherit.
- There's no operator overloading... except for strings. So for pseudo-numeric classes, like BigInteger, you have to do things like
a.add(b.multiply(c)), which is really ugly. - There are no delegates; everytime you need a function pointer you have to implement a factory design.
- Using only interfaces to implement multiple inheritance doesn't allow to share common code through them, unlike "mixins".
-
RuntimeExceptioninherits fromException, but it doesn't make sense: checked exceptions are a special case of unchecked ones, not the contrary. Otherwise said, if I have to catch all the checked exceptions, why don't I have to catch the unchecked ones? -
catchclauses can contain only one exception, causing a programmer to rewrite the same code N times if he wants to react the same way to N different exceptions. - Many standard classes do parameter checking and manually throw unchecked exceptions such as
NullPointerExceptionandIllegalArgumentException. No problem; but what are the assertions for, then? - Every, single, object, has its own synchronization monitor, even those that you never synchronize on, resulting in unnecessary resource consumption. If you declare the dummiest
ArrayList<Integer>, each element of your array will have a synchronization monitor; and of course you will never synchronize on them. Do you have an idea of how many (totally useless) synchronization monitors there are in an instance of the virtual machine running a medium Java program? And in a big program, such as Eclipse or NetBeans? - Some interfaces such as
SerializableandCloneableare used just like annotations: they are empty, and when implemented their only purpose is to indicate some semantics. - Initialization blocks (both static and non-static) can't throw exceptions.
- The
returnstatement is not valid within initialization blocks. - Instance initialization blocks cannot throw checked exceptions, there must be a no-arg constructor throwing those exceptions in its signature.
- Can somebody in the universe explain me why the heck the
clonemethod belongs to theObjectclass instead of theCloneableinterface?? - Cloning is a major pain, because the variable you are cloning must have a type that has a public clone() method (Object's clone() method is protected), which only exists for actual implementation classes, so you can't clone something of an abstract type (which kills abstraction). Also, all the clone() methods in the Java library return type Object for some ungodly reason (instead of the class's own type), so you have to cast it.
- Arrays are objects but don't properly implement
.toString()(if you try to print an array, it just prints hash code gibberish) or.equals()(arrays of the same contents don't compare equal, which causes a headache if you try to put arrays into collections) - Arrays are not type safe:
Object[] foo = new String[1]; foo[0] = new Integer(42);compiles fine but fails at runtime - Arrays don't work with generics: you can't create an array of a variable type
new T[42]or of a parameterized typenew ArrayList<String>[42] - Useful methods like sorting, index of, binary search, etc. are not part of Collection classes, but part of separate "utility classes" like
CollectionsandArrays - Why is
Stacka class, butQueuean interface? - Enums in Java 1.5 are cool, but to use them you have to prefix the enum type, like
MyEnum.SomeValue, because they exist in the enum class's namespace, so they are less convenient than just defining int constants - Unicode escapes are horribly dangerous, because they are substituted before the code is parsed, so they can break your code, for example: (1) if a line-end comment contains a \u000A (line return), the rest of the comment won't be on the same line, and thus won't be in the comment anymore; (2) if a string literal contains a \u0022 (double quote), it ends the string literal, and the rest of the string is now in the actual code; (3) if a \u appears in a comment, and it is not a valid escape (e.g. "c:\unix\home"), it will cause a parsing error, even though it is in a comment
- Convenience functions must be overloaded for every fundamental type (e.g. max(float,float), max(double,double), max(long,long)
- No properties. Simple class definitions are 7 to 10 times as long as necessary.
- Code is cluttered with type conversions. Arrays to lists, lists to arrays, java.util.Date to java.sql.Date, etc.
- No automatic resource cleanup; instead we get have five lines of "allocate; try {...} finally { cleanup; }"
- The Number interface doesn't define arithmetic operations, so it is impossible to write useful generics for Number subclasses.
- No meta-programming.
- Date and Calendar.
- No string join function.
- No array or map literals.
- The reflection API requires multiple lines of code for the simplest operations.
- Programmers can be significantly more productive in Python than in Java
Backbase sucks because:
- Oh really, this subject could take a whole new wiki by itself.
XML sucks
- Attributes are generally limited to unstructured data.
- Its too verbose, too hard for programs to parse, and to hard for people to read.
- It confuses metadata and content.
- It is used for data interchange when it is really just a data encoding format.
XSLT/XPath sucks because:
- It starts numbering from 1. Unlike *every single other* major programming language in use today. Unlike the XML DOM.
- XPath has date maniuplation functions to get the second, minute, hour, date, month, and year from a date-time. But it has no function to get the day of the week, so it's completely useless.
- There is no way to modularize or abstract any XPath expressions, resulting in lots of copied and pasted code.
- conditionals in
test=""attributes of<xsl:if>and<xsl:when>items. - sorting conditions in
<xsl:sort>
- conditionals in
- When your context is the contents of a node-set, the
key()functions defined on the entire input XML do not work. What's dumber, no error message is produced; yourselect="key(...)"just silently returns the empty set. It should at least say "key() does not work inside node-sets" or perhaps "no such key in context node-set" - The
select="",value=""andmatch=""attributes do basically the same thing. And their use is arbitrarily exclusive; you must use the correct attribute in the correct place, and if you use the wrong one, the node fails without any warning. These three attributes should have the same name. - If you import a function (like
str:replace()) but fail to import it correctly or fully (like leaving off the namespace), and then call that function, no error is raised whatsoever. The function simply evaluates to it's last argument. How could this ever be desirable behavior? If I'm calling a function that's somehow not available, obviously that is always a programmer error, and some warning should be raised. - There's no way to construct a custom set of values and then iterate over it at runtime, although there is a way to construct a single custom value and then operate on it at runtime. In other words, the language has no list/array/tuple/dict/hash/set/iterable/collection type.
- It allows '-' in identifiers, but the parser isn't smart enough to figure out when you mean 'minus' instead of - . If you're going to allow '-' as an identifier character and as an operator, at least make it so that the string following the identifier character '-' has to follow the standard identifier pattern,
[a-zA-Z_][a-zA-Z0-9_]*. Don't make this one use of whitespace significant in a language where whitespace is usually insignificant around operators. Nobody is ever going to want a variable name like$foo-100, because it looks just like $foo - 100.-
$foo-baris rightly interpreted as a variable name -
$foo - 100is rightly interpreted as subtraction -
$foo+100and$foo + 100are rightly interpreted as addition -
$foo-100is wrongly interpreted as a variable name
-
- There is no concept of types whatsoever. Everything is fundamentally a string. This means that even things that are intrinsically typed are treated as strings fundamentally. For example, sorting on the number of child nodes sorts by string order, not numeric order, even though counting is an intrinsically numeric operation.
<xsl:sort select="count(*)"/> <!-- sorts like this: 10, 11, 1, 23, 20, 2, 37, 33, 31, 3, 4, 5, 6, 78, 7, 9 -->
- There are too many levels of syntactic and semantic interpretation:
- Parse XML syntax (ensure that all nodes are closed, etc)
- Parse XSL syntax (ensure that nodes that must be under/contain other nodes are present, verify that all xsl:foo node names are valid, etc)
- Parse XSL semantics (find the correct attributes under each node type, etc)
- Parse XPath syntax (entirely contained inside attribute values, cannot be parsed earlier)
- Parse XPath semantics
CSS sucks because:
- Hello? Rounded corners? Mac OS had them in 1984. (CSS3 introduces border-radius)
- Can only set one background image. (CSS3 supports multiple backgrounds)
- Just too many ways to say the same thing.
- Can't specify stretchable background images. (CSS3 introduces background-size and background-clip)
- text-align:justify really means "left justify". No way to right justify or center justify.
- No way to make vertical or angled text. (CSS3 introduces rotate)
- vertical-align:middle doesn't work with block elements, although it works with inline elements and table elements. This leads to people suggesting display:table and display:table-cell and it means you have to style the wrapper as well. WTF.
- Horizontally aligning block elements was not intended to be supported and is only hackish at best (margin: 0 auto).
- Can float an item to the left or the right. But you cannot float items to the center.
- float is only horizontal; there is no equivalent vertical operation. (OK, it's actually a flow operation, go figure.)
- Similarly, there is no vertical equivalent to clear.
- No way to modularize or programmatically generate colors. If you want text and borders to use the same color, you have to write that color twice.
- No way to modularize or programmatically generate lengths. Can't say:
{ width:50% - 2px; }
- The CSS spec is contradictory with regard to identifiers:
- The syntax says that identifiers don't allow uppercase characters anywhere but in the first character:
- ident {nmstart}{nmchar}*
- nmstart [a-zA-Z]|{nonascii}|{escape}
- nmchar [a-z0-9-]|{nonascii}|{escape}
- Section "4.1.3 Characters and case:" says:
- In CSS2, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [A-Za-z0-9] and ISO 10646 characters 161 and higher, plus the hyphen (-); they cannot start with a hyphen or a digit."
- The syntax says that identifiers don't allow uppercase characters anywhere but in the first character:
- Why diverge from the standard identifier format, [a-zA-Z_][a-zA-Z0-9_]*, which has been in use since the 1970s?
- CSS Considered Unstylish
- Will we ever have alpha masks? Webkit does it but...
- Supporting vendor prefixes suck. Pretending -webkit- is the only vendor prefix sucks even more.
- There's SASS, LESS and Stylus. Take every single feature. Every one is a CSS wtf. (indent-based syntax should be optional, though).