2019-12-19
Comparing these languages is a rare thing, because these languages are very different and serve different purposes. But when I needed to learn them, while already knowing C++, I really needed a simple comparison table for an easier start. I did not find such comparison, so I created it. I hope this comparison table is useful for developers, which already have experience in some of the following languages, and are learning one of these languages.
You can find more details and examples in the following articles:
Feature | C++ | Go | Java | Javascript | PHP | Python |
---|---|---|---|---|---|---|
Created | 1985 Bjarne Stroustrup 1972 Dennis Ritchie (C) |
2009 Google | 1995 Sun (Oracle) | 1995 Netscape | 1995 Rasmus Lerdorf | 1991 Guido van Rossum |
Purpose | compiled object-oriented, generic, functional, low-level memory manipulation | like C but with memory safety, garbage collection, structural typing and CSP-style concurrency | high-level object-oriented implementation-independent | high-level just-in-time compiled multi-paradigm, prototype-based object-orientation | general-purpose web-development | interpreted high-level general-purpose |
Types | ||||||
Type | statically typed | statically typed | statically typed | weakly dynamically typed (variables can be implicitly coerced to unrelated types) | weakly dynamically typed with static typed features (strict_types) | strongly dynamically typed (variables cannot be implicitly coerced to unrelated types) |
Primitive numeric data types | int and uint up to 64 bit. float up to 64 bit. | int and uint up to 64 bit. float up to 64 bit. | int up to 64 bit. float up to 64 bit. | int stored as 64 bit float (up to 53 bit without precision loss). | int and float is 64bit on x64 hardware. int converted to float if result is big | int with unlimited precision. float up to 64 bit. |
Boolean literals | true false |
true false |
true false |
true false |
true false (case insensitive) |
True False |
Type coercion | Numeric | no | Numeric widening (byte ➞ short ➞ int ➞ long ➞ float ➞ double) | Numeric, strings, objects etc. (disabled with ===) | Numeric, strings etc. (disabled with ===) | Numeric, container to bool |
Immutability | All objects are mutable if const is not used. Const object is immutable if it has no mutable members and const_cast is not used. | Immutable: string | Immutable: all wrappers (Boolean, Short, Integer, Long, Float, Double, Byte, Char, String) | Immutable: string, number, boolean. Mutable: objects and arrays. | Immutable: number, boolean, final class. | Immutable: int, float, complex, string, tuple, frozen set, bytes. Mutable: list, dict, set, byte array. |
Const meaning | immutable pointer and/or value | immutable binbind | final (immutable binding) | immutable binding | const / define (immutable binding) | - |
Default slicing behavior | vector copy constructor, span is view of vector |
[:] creates slice pointing to same array | copyOfRange | slice copies immutable elements and object references | array_slice and = copies elements or references | [:] copies immutable elements and object references islice creates view |
Union | union | - | - | - | - | - (use struct to interpret bits differently) |
Numerical type size guarantee | no (depends on platform) but has fixed width types |
no (depends on platform) but has fixed width types |
yes | no (not sure what will happen to float64 on 32 bit OS) | no (depends on platform) | yes (switches to bignum automatically) |
Pointers and address operator | yes (with arithmetic) | yes (no arithmetic unless unsafe) | no | no | no | no |
Statements and expressions | ||||||
Logical operators | ! && (short-circuit) || (short-circuit) |
! && (short-circuit) || (short-circuit) |
! & | && (short-circuit) || (short-circuit) |
! && (short-circuit) || (short-circuit) |
! && (short-circuit) || (short-circuit) |
not and (short-circuit) or (short-circuit) |
Ternary operator | test ? a : b | - | test ? a : b | test ? a : b | test ? a : b | a if test else b |
Goto | goto | goto | - | - | goto | - |
Strings | ||||||
String concatenation operator | + | + | + | + | . (dot) | + |
Internal string encoding | No (bytes) | No (bytes) | UTF-16 | UTF-16 | No (bytes) | Most compact of Latin-1, UCS-2 or UCS-4 |
Source file encoding | any | UTF-8 | UTF-8, UTF-16, or UCS-2 | any | any | any |
Convert non-int string to int | stoi("a") -> exception | Integer.parseInt("a") -> exception | parseInt("a") returns NaN | int("a") -> exception | ||
Detect formatting wrong type / number of args | Manual with __attribute__((format)) | Automatic | Automatic | not needed | not needed | not needed |
Mutable string | std::string, char* | strings.Builder or bytes.Buffer | StringBuffer (synchronized), StringBuilder | Not needed (strings concatenation is optimized) | Strings are mutable | Not needed (strings concatenation is optimized) For older Python 2 use ''.join() |
Symbol ' | character | character | character | string or character | unparsed multiline string | string or character |
Symbol " | string | string | string | string or character | parsed multiline string | string or character |
Symbol ` | - | raw string | multiline string | multiline template literal | execute | deprecated alias for repr() |
Multiline string | - | - | - | `...` (template) | '...' or nowdoc "..." or heredoc |
"""...""" or '''...''' |
Raw string literal | - | - | - | - | - | r'...' or r"..." |
Raw multiline string literal | R"(...)" | `...` (CR is removed) | `...` | String.raw`...` (template) | - | r"""...""" or r'''...''' |
Variable declarations | ||||||
Local variable declaration | int x = 1 | var x = 1 x := 1 |
int x = 1 | let x = 1 | $x = 1 | x = 1 |
Variable declarations are hoisted | no | no | no | hoisted | no declarations | no declarations |
Functions | ||||||
First class function support | full | yes, except named nested functions | yes, except named nested functions and partial application | full | yes, except named nested functions and partial application | yes, but nested anonymous functions are expressions only |
Closure (stateful function) | return lambda to std::function, operator() |
return anonymous function | return nested function | inner anonymous class return lambda expression |
return nested function | |
Default argument passing | By value |
By value | By value (primitive) Reference by value (object) |
By value (primitive) Reference by value (object) |
By value (primitive) Reference by value (object) |
|
Can change passed reference | yes, if passed reference to pointer (&*) or pointer to pointer (**) | - | - | - | - | |
Variable number of arguments | ... | Varargs ... |
*args, **kwargs | |||
Function overloading | yes (not by return type) | - | yes (not by return type) | - | - | |
Implicit functions inlining | yes | yes | yes | - | no (PyPy does) | |
Explicit functions inlining | inline | - | - | - (in JS inline function is named anonymous function) | - | |
Function declarations are hoisted | no | no | no | hoisted | hoisted | no |
Function (not lambda) declaration | statement | statement | statement | expression (returns value) | statement | statement |
Lambda functions | Yes | Anonymous function | Lambda expression | Function assignment. Arrow functions. | Anonymous function | Cannot contain statements, only expressions. Do not create their own scope. Cannot raise or catch exceptions, have if blocks or loops. Cannot have multiple return points |
Named arguments of function | No | No | No | Using destructuring: function f({x, y} = {x:1, y:2}) {} |
Yes (starting from PHP 8) | Yes |
Missing/extra parameters in a function call | Will not compile | Missing parameters get value of 'undefined'. Extra parameters get into 'arguments' object. | Exception | |||
Generator functions (yield output) | no | yes | yes | |||
Coroutines (yield output and input) | C++20 or libraries | yes (goroutine) | no (so far) | yes | yes | |
Nothing | ||||||
Check if variable was declared | ||||||
Set variable to nothing | Only with std::optional | nil | null Check for null: === null Check for null or undefined: == null |
null | None Check for None: is None |
|
Undefined (uninitialized) variables | Variable can be undefined if not initialized, but it will return random value if used, instead of 'undefined'. | Unitialized variables are zero | Unitialized fields are zero/null Compile error if reading uninitialized local variable |
undefined Check for undefined: typeof x === 'undefined' Check for null or undefined: == null |
null if used before initialization | All variables are initialized - so there are no undefined variables. |
Assignment | expression (returns value) | expression (returns value) | statement (does not return value) | |||
Scope | ||||||
File scope | Files do not have their own scope, but you can use static and unnamed namespace to create one: namespace { a = 1; } |
Files do not have their own scope, but you can create separate scope with anonymous function: (function(){ let a=1; })(); or !function(){ let a=1; }(); |
Files have their own scope | |||
Namespace creation | namespace, class, function, block | class, function, block | function | namespace (contains classes, functions, consts), class, function | function, class, module | |
Global functions and variables | yes | yes | no (only in classes) | yes | yes | |
Access global variable | direct | direct | no global scope | direct | GLOBAL $x; | direct |
Declare variable in global scope from local scope | impossible | impossible | no global scope | x = 1 | $GLOBALS['x'] = 1; | global x x = 1 |
Object-oriented programming | ||||||
Object oriented programming | class-based | methods, interface, embedding | class-based | prototype-based | class-based | |
Private members | yes | yes | - (only private variables and functions inside constructor) | - | ||
Can call constructor or method without instantiating an object | no | C.f(o) (have to pass some object instead of self) | ||||
Accessing object members | member (or this->member if ambiguous) | receiver in method declaration | member (or this.member if ambiguous) | this.member | self.member | |
Can attach function to an object method | no | no classes | o.func = function() {}; | obj.f = f.__get__(obj) | ||
Multiple inheritance | yes | no inheritance (but multiple embedding) | single (can inherit multiple interfaces) | single | yes | |
Overload operators | yes | no classes | no | |||
Concurrency | ||||||
Concurrency | Concurrent - can use all processor cores | Concurrent - can use all processor cores | Concurrent - can use all processor cores | Concurrent (web workers and worker threads) - can use all processor cores | pthreads (threads), popen (processes) | Limited (threading module is not concurrent if you cannot release GIL with i/o operation or external code, multiprocessing module uses processes instead of threads, Twisted uses event model) |
Thread-local storage | thread_local | - (can use gls package) | ThreadLocal | yes (in web worker) | threading.local | |
Detect races | -fsanitize=thread | go -race | FindBugs, ConTest | NodeRacer | manual | ? |
Data structures | ||||||
Hash tables | std::unordered_map | Object and Map | dict, defaultdict | |||
Array of different-typed elements | std::vector<std::variant<int, double, ...>> | array | list | |||
Immutable structure | const | e.g. unmodifiableList | freeze any object | tuple,frozenset,frozendict | ||
Fixed size modifiable array | C array[], std::array | array[] | array[] | seal | - | |
O(1) growing array | vector | slice[] | ArrayList or Vector (thread-safe) | Array | list | |
Forward linked list | forward_list | - | - | - | - | |
Doubly linked list | list | list | LinkedList | - | - | |
Hash set | unordered_set | map[type]bool, golang-set, intsets | HashSet | can use Object | set | |
Hash set with insertion order | - | - | LinkedHashSet | Set | can use OrderedDict | |
Hash map | unordered_map | map | HashMap | Object | dict | |
Hash map with insertion order | - | orderedmap | LinkedHashMap | Map | OrderedDict | |
Sorted set | set (balanced BST) | gods.treeset | TreeSet (balanced BST) | SortedSet (3rd party: balanced BST) | SortedSet (3rd party: set + list of sorted lists of keys) | |
Sorted muiltiset | multiset (balanced BST) | - | TreeMultiset (Google) | - | - | |
Sorted map | map (balanced BST) | gods.treemap | TreeMap (balanced BST) | SortedMap (3rd party: balanced BST) | SortedDict (3rd party: dict + list of sorted lists) | |
Sorted multimap | multimap (balanced BST) | go-multimap | MultiMap | Object with arrays as values | defaultdict(list), multidict (3rd party) | |
Double-ended queue with O(1) indexing | deque | deque | ArrayDeque, LinkedList | Deque (3rd party) | deque | |
Stack | adaptor for dequeue, vector or list | slice[] | Stack (subclass of Vector) | Array | use list, LifoQueue or deque | |
Queue | adaptor for deque or list | list, deque | Deque | Array (slow shift) | deque, Queue (thread-safe) | |
Priority queue | priority_queue (based on vector or deque) | heap (binary heap) | PriorityQueue | (3rd party) | heapq | |
Array with elements of different type | std::vector<std::any>, std::vector<std::variant> |
[]interface{} | Object[] arr | Array | list | |
Error handling | ||||||
Exceptions | try ➞ throw ➞ catch | panic ➞ defer ➞ recover | try ➞ throw ➞ catch ➞ finally | try ➞ throw ➞ catch ➞ finally | try ➞ raise ➞ except ➞ else ➞ finally | |
Print stacks on failure | install SIGSEGV handler, insert backtrace into exception |
automatic, debug.PrintStack() |
Thread .currentThread() .getStackTrace() |
console.trace(), new Error(); .stack |
automatic, get from exception |
|
Memory management | ||||||
Garbage collection | no | yes | yes | yes | yes | |
Stack/heap allocation | Explicit (new). Objects can be in heap or stack. | Implicit (escape analysis) | Explicit (new). Objects always in heap. |
Implicit | Implicit | Implicit |
Default stack size | static 8MB | dynamic 8KB-1GB | static 512KB | static | static | static |
Environment | ||||||
Entry point | int main (int argc, char *argv[]) | func main() | public static void main(String args[]) | first line | first line | if __name__ == "__main__": |
Function before entry point | __attribute__ ((__constructor__)) void init(void) | func init() | static {} | - | - | - |
Command-line arguments | main() arguments from 1 | os.Args[1:] | main() arguments from 0 | process.argv from 1 | $argv from 1 | sys.argv[1:] |
Code management and integration | ||||||
Linking | header=file (include) or module=file (import) | package=files (import) in module | package=files (import) in module, service, image, layer | module=file (import) in package=folder | module=file (import) in package=folder | |
Define macro | #define | no | no | |||
Preprocessor and macros | yes | - (but can substitute symbols at build time with -X flag) | - | - | - | |
Eval | - | - | - (can use ScriptEngine to evaluate JS) | eval | eval | |
Low level programming | Inline assembly | Link SWIG, C, Asm | Link C, Asm with JNI | WebAssembly | PHP extension | Cython, SWIG, ctypes |
Performance | ||||||
Execution time | 2 | 4 | 4 | 4 | 100 | |
Compilation time | slowest to machine code | fastest to machine code | fast to byte code | no (interpreted) | no (interpreted) | |
Can skip out-of range checks | yes (indexing [] by default skips, at() checks) | - | - | - | - | |
Tools | ||||||
Testing | many frameworks | testing | JUnit, TestNG | pytest, unittest | ||
Debug | gdb | Delve | jdb | Chrome | phpdbg | pdb |
Character | char (1 byte) | rune (4 bytes) | char (2 bytes) | no (string only) | no (string only) | no (string only) |
Digit separator in literal | 100'000 (since C++14) |
100_000 (since 1.13) |
100_000 (since SE 7) |
100_000 (since ES2021) |
100_000 (since 7.4) |
100_000 (since 3.6) |
Static variable in function | yes | no (use global or closure) | no (use static class variable or instance variable) | no (use closure or function property) | yes | no (use global or function attribute or closure) |
Variable with same name in nested block | hides external | hides external | compilation error | hides external | rewrites external variable value (if same function scope or imported with GLOBAL) | 1. hides external without nonlocal 2. rewrites external variable value (if same function scope or imported with nonlocal) |
Case sensitive names | ||||||
Integer division | integer / integer | integer / integer | integer / integer | Math.floor(x / y) | floor($x / $y) | x // y (python 3) x / y (python 2) |
Integer expressions promotion | byte, short, char to int |
|||||
Type inference | auto a = b; | a := b | var a = b; | always | always | always |
Prefix increment ++x | expression | - | expression | expression | expression | - |
Postfix increment x++ | expression | statement | expression | expression | expression | - |
Assignment is expression | yes | no | yes | yes | yes | := only |
Labeled break and continue | break label; continue label; |
|||||
New object | ||||||
Copy object | ||||||
Reference to object | ||||||
Default member access | struct: public class: private |
accessible by the classes of the same package | ||||
Static member access | Class::Member | Class.Member | ||||
Nested class can access private members | yes | |||||
Anonymous class | yes | yes | ||||
Class nested in function | yes | yes | ||||
Default parameter values | yes | no | no | |||
Division by zero exception | no | yes | ||||
Exiting main thread finishes all | yes | yes | no | |||
Generics | templates | generics | ||||
Lambda syntax | x -> x (x, y) -> { return x; } |
|||||
Can modify captured local variable | no (only instance variable through capturing this) | |||||
Members visibility | ||||||
Base class constructor called automatically | yes | no | ||||
Object identity and reference identity |