YourLanguageSucks
From TheoryOrg
Contents |
CSS sucks because:
- Hello? Rounded corners? Mac OS had them in 1984.
- Can only set one background image.
- Just too many ways to say the same thing.
- Can't specify stretchable background images.
- text-align:justify really means "left justify". No way to right justify or center justify.
- No way to make vertical or angled text.
- No way to vertically align block elements.
- Horizontally aligning block elements was not intended to be supported and is only hackish at best.
- 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.
- 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
- It still sucks that CSS 2 didn't have these, even though they're being added in CSS 3:
- Gradients?
- Transparency?
Python Sucks because:
- 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 (You could use decorators to simulate dynamic default arguments)
- No labeled break or continue
- if you mispell a variable name you don't get notified at compile time
- from python docs:
!=can also be written<>(see php). Note: in Python 3.x there's only!=
PHP sucks because:
- (PHP4)
'0',0, and0.0are false, but'0.0'is true - (PHP4)
NULLis not false -
__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
- here doc syntax
- There is no way to find if vars hold refs to the same object. (well since
__toString()is broken I guess you could do((string) $obj1) == ((string) $obj2)but that is stupid.) - 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... It is often up to you to figure out when features were added if they forget to mention it.
- 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 -
$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 function, no error is raised; instead, it is interpreted as a string "nonexistent_function_name"
- if you send the wrong number of arguments to a 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, date, 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. Even more surprising, it does raise a syntax error on07A. - 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
- OMFG, it's stupid. How stupid? *This* stupid:
#define HASH_KEY_NON_EXISTANT - 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
- there's one
is_typefor eachtype:is_int,is_float,is_string, etc. to check for a proper type, rather thanis_instance_of(obj, type)disputed on discussion page - 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 (deprecated in PHP 6)
- 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 usually are defined using a function, so this can generate errors:
define("123 spam?Yes!", "OMG: a bad constant name"); - constants can only be defined for scalar values (booleans, integers, 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"
-
'Z'+ 1gives'AA', but strings in PHP contain characters, and characters are in the LATIN1 charset range, not in'A'..'Z' -
'Z'+ 1gives'AA', but'AA' - 1isn't possbile to have back'Z' -
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 - there's
is_type(such asis_int) for built-in types, andinstanceoffor user defined ones (using classes) -
NULL--has no effect, butNULL++gives1 -
++and--cannot be applied to booleans disputed on discussion page - 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
- include can be used like a function call which return values, but using parentheses to call it like any other function won't work. It must be called without parentheses.
- 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
- class definition can be broken into multiple parts only inside method definition.
- methods can be called both as instance methods (with
$thisspecial variabile defined) and class methods (withself) - 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
- must be used the special name
parentto access members of the base classes, even if they... aren't parents:
class A
{
function example()
{
echo "example of A\n";
}
}
class B extends A
{
}
class C extends B
{
function example()
{
parent::example(); // Ehi, it's my grandpa!
}
}
$c = new C;
$c.example();
- if the class of an object which must be unserializing isn't defined when calling
unserialize(), an instance ofstdClasswill be created instead, loosing any reference to the original class - 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);
$this->echoName();
}
function echoName() {
echo "\n", $this->name;
}
function setName($name) {
$this->name = $name;
}
}
$bar1 = new Foo('set in constructor');
$bar1->setName('set from outside'); // 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
- exceptions in a destructor cause fatal errors
- instance variables can be declared with or without
varkeyword - static variables cannot be accessed from an instance; they must be accessed using the $class::variable scope operator
- static methods can be accessed from an instance
- foreach applied to an object iterates through its variables by default
- to inspect a class using reflection's API, an instance must first be created
- static references to the current class like self:: or __CLASS__ are resolved using the class in which the function are defined:
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!
- name resolution with namespaces is a nightmare
-
@operator cannot be applied to&new, so exceptions will cause a fatal error - 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"
- source aren't compiled into bytecode or similar, so every time they are loaded must be interpreted, leading to longer loading times and execution speed
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
JavaScript sucks because:
- 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;
}
- 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
- Passing the wrong number of arguments to a function? No problem, it just ignores them!
function foo(array1, array2){
/* do something */
}
foo([1,3,4], 4,5,6,7); /* Whoops! forgot my []s */
function bar(array1, array2){
if (arguments.length != 2) {
barf;
}
/* do something */
}
bar([1,3,4], 4,5,6,7); /* BARF! */
Object-oriented programming sucks because:
Some points in this section have been disputed on the discussion page.
- "Object-oriented programming is an exceptionally bad idea which could only have originated in California." --Edsger Dijkstra
- Object oriented programming has been shown to have no significant difference in productivity than standard procedural programming.
C++ sucks because:
Some points in this section have been disputed on the discussion page.
- 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.
- The specification has grown to over 600 pages, which reflects the bulky nature of C++.
- 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.
- The nature of C++ has led developers to write compiler dependent code, creating incompatiblity between different compilers and even different versions of the same compiler.
- No widely used OS supports the C++ ABI for syscalls.
- C++ supports 'goto'.
- What is 's', a function or a variable?
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!!
- There's a moment in every C++ programmer's life where he wonders why, why, switch case fall-through has been invented: it's completely useless, and if you forget a break you introduce a bug silently.
- Not to mention a classic:
if (a = b) // forgot an =; condition is true if b != 0
{
...
- 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 goddamn overloadedoperator char* (). - 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. - 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
C# sucks because:
This section is only a stub. You can contribute by subscribing and expanding it.
- Supports 'goto'.
- It's a Microsoft product
Java sucks because:
Some points in this section have been disputed on the discussion page.
- 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.
- 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.
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.
Perl sucks because:
This section is only a stub. You can contribute by subscribing and expanding it.
- "Perl is worse than Python because people wanted it worse" (Larry Wall, creator of Perl).

