7 axes that matter
Typing, paradigm, memory model, runtime, autograder compatibility, error handling, concurrency. Side by side per language.
Comparison
Java, Python, C++, JavaScript, C, and Assembly compared across 7 axes that matter for coursework. With autograder-compatibility notes per language.
Overview
At a glance
Typing, paradigm, memory model, runtime, autograder compatibility, error handling, concurrency. Side by side per language.
Java, Python, C++, C, JavaScript, Assembly. Why each one shows up in coursework and where it wins.
Same algorithm in 4 languages. Three decision rules for which language to submit when the brief allows a choice.
Section 1 of 13
Computer science programs converge on the same 6 languages because each illustrates a category of computing. Java for object-oriented design and bytecode runtimes. Python for algorithm prototyping and data work. C++ for performance with abstraction. C for systems programming and how the machine actually works. JavaScript for web and event-driven programming. Assembly for what the CPU sees after every layer above peels away.
CS61B at Berkeley uses Java for data structures because the strict typing pairs well with introducing generics and class hierarchies. CS50 at Harvard uses C in the first half so students see manual memory management, then Python in the second half so they see how a higher-level language smooths the same operations. MIT 6.006 uses Python so the focus stays on the algorithm and not the boilerplate.
Section 2 of 13
Static typing catches type mismatches before the program runs. Dynamic typing catches them at the moment the bad value flows through. Strong typing refuses implicit conversions across categories (no "3" + 4). Weak typing allows them.
| Language | Static or dynamic | Strong or weak | Type inference | Optional types |
|---|---|---|---|---|
| Java | Static | Strong | Partial (var since Java 10) | No |
| Python | Dynamic | Strong | No | Yes (PEP 484 type hints + mypy) |
| C++ | Static | Strong (with implicit numeric conversions) | Yes (auto) | No |
| C | Static | Weak (implicit pointer-int conversions) | No | No |
| JavaScript | Dynamic | Weak ("3" + 4 === "34") | No | Yes (TypeScript) |
| Assembly | Untyped | N/A | N/A | N/A |
Strong dynamic typing (Python) catches the worst footguns at runtime. Weak dynamic typing (JavaScript) silently produces garbage. This is why Python is the recommended first language: errors fail loud, not silent.
Section 3 of 13
Every language listed supports imperative code (the default style). Beyond that:
| Language | Object-oriented | Functional | Procedural | Default style |
|---|---|---|---|---|
| Java | Native, single inheritance | Streams + lambdas since 8 | Static methods | OO |
| Python | Native, multiple inheritance with MRO | First-class functions, comprehensions | Module-level functions | Multi-paradigm |
| C++ | Native, multiple inheritance | Lambdas, ranges since 20 | Native | OO + procedural |
| C | Via convention (struct + function pointers) | Limited (function pointers) | Native | Procedural |
| JavaScript | Prototype-based, ES6 class sugar | First-class functions, closures | Native | Multi-paradigm |
| Assembly | No | No | Effectively procedural | Direct hardware control |
OO courses (CS61B, CS18 at Brown) use Java because the language enforces the paradigm. Functional courses (CS3110 at Cornell, Berkeley CS61A) use Scheme, OCaml, or Racket because they enforce the functional discipline. Multi-paradigm courses pick Python so each paradigm can be introduced in turn.
Section 4 of 13
Who frees the memory the program allocates? Three answers across the 6 languages.
| Language | Allocation | Deallocation | Garbage collector | Common pitfalls |
|---|---|---|---|---|
| Java | Implicit on new | GC (G1 or ZGC) | Yes | Long-lived references holding short-lived data alive |
| Python | Implicit on assignment | Reference counting + cycle GC | Yes | Circular references in C extensions, large captured locals |
| C++ | Explicit (new) or RAII (smart pointers) | Explicit (delete) or destructor | No | Double-free, use-after-free, leaks |
| C | malloc | free | No | Leaks, use-after-free, double-free, NULL deref |
| JavaScript | Implicit on object literal or constructor | GC (mark-sweep) | Yes | Closures holding DOM nodes alive, listener leaks |
| Assembly | Manual stack frame, syscalls for heap | Manual | No | Everything is your problem |
Manual memory management (C, C++) is the source of the buffer overflows, use-after-free, and double-free bugs in the common compiler errors guide. GC removes the entire bug class at a cost of unpredictable pause times and higher peak memory.
Section 5 of 13
The execution model determines startup time, peak throughput, and how predictable the runtime is.
| Language | Compilation | Runtime form | Startup time | Steady-state speed (vs C baseline) |
|---|---|---|---|---|
| C | AOT to native | Native binary | ~1 ms | 1x (baseline) |
| C++ | AOT to native | Native binary | ~1 ms | 1x |
| Java | AOT to bytecode, JIT at runtime | JVM bytecode + native after warmup | ~100 ms (JVM startup) | 1.5x to 3x after warmup |
| JavaScript | JIT (V8, SpiderMonkey) | JIT-compiled native after warmup | ~10 ms (Node) to ~100 ms (browser) | 2x to 5x after warmup |
| Python | Bytecode at first run, then interpreted | CPython interpreter | ~30 ms | 30x to 100x slower |
| Assembly | Assembled to native | Native binary | ~0 ms | 1x (or faster with hand-tuned) |
Coursework that measures wall-clock time uses C, C++, or Java. Coursework that measures correctness uses Python so the autograder is not dominated by JIT warmup or compile time. Gradescope test timeouts default to 30 seconds in Python and 10 seconds in Java; the same algorithm has 3x more headroom in Python because the harness expects the slowdown.
Section 6 of 13
| Language | Coursework wins | Industry wins |
|---|---|---|
| Java | OOP, data structures, software engineering, distributed systems | Backend services (Spring Boot), Android (legacy), big data (Hadoop, Kafka) |
| Python | Algorithms, AI/ML, data analysis, scripting, intro CS | ML (PyTorch, TensorFlow), data science (Pandas, NumPy), web (Django, FastAPI), DevOps scripts |
| C++ | Systems programming, game engines, performance-critical algorithms | Game engines (Unreal), HFT, embedded systems, compilers (LLVM) |
| C | Operating systems (xv6), embedded, intro to systems (CS50) | Linux kernel, embedded firmware, databases (Postgres, Redis), drivers |
| JavaScript | Web programming, full-stack capstone projects | Web frontend (React, Vue), backend (Node), serverless (AWS Lambda) |
| Assembly | Computer architecture (CS61C), reverse engineering, compiler backends | OS interrupt handlers, security research, ultra-low-level optimization |
Section 7 of 13
How long until a student writes a non-trivial program that does something real? Order from fastest to slowest:
print("hello") is a complete program.public class Main, public static void main, explicit types. The boilerplate trades off against compile-time safety.Section 8 of 13
The autograder is the actual rubric grader. Compatibility is per-language and per-version. Gradescope is the dominant autograder for university CS courses; AutoGrader (Berkeley's in-house) is used in CS61 series; HackerRank and LeetCode are interview-prep autograders.
| Language | Gradescope | AutoGrader (Berkeley) | HackerRank | Common version pin |
|---|---|---|---|---|
| Java | OpenJDK 17 default, 21 selectable | Java 17 | Java 8, 15, 17 | Java 17 (LTS) |
| Python | 3.10 default, 3.11 and 3.12 selectable | 3.10 | 3.10 | Python 3.10 |
| C++ | g++ 11, C++17 default, C++20 selectable | g++ 11, C++17 | g++ 11, C++17 | C++17 |
| C | gcc 11, C11 default | gcc 11, C11 | gcc 11 | C11 |
| JavaScript | Node 18 LTS | Rarely used | Node 18 | Node 18 |
| Assembly | x86-64 AT&T syntax, RISC-V supported | RISC-V (CS61C) | Not supported | x86-64 or RISC-V |
-XX:+ShowCodeDetailsInExceptionMessages locally so NPEs name the variable.std::unordered_map iteration order varies across libstdc++ vs libc++. Use std::map for deterministic test output.printf with mismatched format specifiers passes locally on some systems, fails on Gradescope under -Wformat -Werror.Section 9 of 13
To make the comparison concrete, here is iterative Fibonacci in all 4 stdlib languages. The same algorithm; different conventions per language.
# Python: 5 lines, no types, immediate
def fib(n):
a, b = 0, 1
for _ in range(n):
a, b = b, a + b
return a
print(fib(10)) # 55 // Java: full ceremony for the same 5 lines
public class Fib {
public static long fib(int n) {
long a = 0, b = 1;
for (int i = 0; i < n; i++) {
long t = a + b;
a = b;
b = t;
}
return a;
}
public static void main(String[] args) {
System.out.println(fib(10)); // 55
}
} // C++: explicit types, no main wrapper class
#include <iostream>
#include <cstdint>
std::int64_t fib(int n) {
std::int64_t a = 0, b = 1;
for (int i = 0; i < n; i++) {
std::int64_t t = a + b;
a = b;
b = t;
}
return a;
}
int main() {
std::cout << fib(10) << '\n'; // 55
return 0;
} /* C: same as C++ minus iostream */
#include <stdio.h>
#include <stdint.h>
int64_t fib(int n) {
int64_t a = 0, b = 1;
for (int i = 0; i < n; i++) {
int64_t t = a + b;
a = b;
b = t;
}
return a;
}
int main(void) {
printf("%ld\n", fib(10)); /* 55 */
return 0;
} Section 10 of 13
How each language handles parallelism shapes the kinds of problems it suits.
| Language | Threads | Async | GIL or equivalent | Typical pattern |
|---|---|---|---|---|
| Java | Native OS threads + virtual threads (JEP 444, Java 21) | CompletableFuture, Project Loom | No GIL | Thread pool + BlockingQueue, or virtual threads |
| Python | OS threads, limited by GIL | asyncio | Yes (CPython GIL) | asyncio for I/O, multiprocessing for CPU |
| C++ | std::thread, std::jthread (C++20) | std::async, coroutines (C++20) | No | std::async + futures, or raw threads + mutex |
| C | pthreads, C11 threads.h | None native (use libuv or epoll) | No | pthread_create + mutex + condvar |
| JavaScript | Web Workers, Worker Threads in Node | Native Promises, async/await | Single-threaded event loop per worker | async/await + Promise.all |
| Assembly | Manual via syscalls (clone, fork) | None | Manual | Direct hardware fences (MFENCE, etc.) |
The CPython GIL is the single most-discussed performance constraint in Python. It serializes Python bytecode execution across threads, so CPU-bound multi-threaded Python code does not scale. PEP 703 (free-threaded CPython, 3.13 experimental) removes the GIL but at the cost of slower single-threaded performance. Until free-threaded CPython is the default, use multiprocessing for CPU-bound parallelism in Python.
Java 21 virtual threads (Project Loom) deliver millions of cheap green threads on a small OS thread pool. The same code that uses one OS thread per request now uses one virtual thread per request, scaling to 100,000 concurrent requests without server-tuning hell. This is the largest concurrency model change in Java since 1.0.
Section 11 of 13
How a language reports failures shapes its idiomatic structure.
| Language | Mechanism | Checked at compile? | Typical idiom |
|---|---|---|---|
| Java | Checked + unchecked exceptions | Checked yes | try/catch/finally, try-with-resources |
| Python | Exceptions | No | try/except/else/finally, raise from |
| C++ | Exceptions + std::expected (C++23) | No | try/catch, RAII for cleanup |
| C | Return codes (-1, NULL, errno) | No | Check return, goto cleanup label |
| JavaScript | Exceptions + Promise rejection | No | try/catch (sync), .catch (async), or try/await |
| Rust (not covered above but worth comparing) | Result + Option types | Yes | match, ? operator |
Java's checked exceptions require either catching or declaring every IOException-like failure. The discipline catches bugs the other languages let escape to runtime. The cost is verbosity: simple file I/O wraps in 3 lines of try { } catch (IOException e) { throw new RuntimeException(e); } ceremony, which is why Project Lombok adds @SneakyThrows and Kotlin removes checked exceptions entirely.
C has no destructors, exceptions, or finally. The standard pattern is a single goto label at the function bottom that frees all resources. Critics call this anti-pattern, but it is the only mechanism C provides for guaranteed cleanup across error paths.
/* C: goto cleanup is idiomatic, not bad style */
#include <stdio.h>
#include <stdlib.h>
int process_file(const char *path) {
FILE *f = NULL;
char *buf = NULL;
int rc = -1;
f = fopen(path, "r");
if (!f) goto cleanup;
buf = malloc(4096);
if (!buf) goto cleanup;
if (fread(buf, 1, 4096, f) != 4096) goto cleanup;
rc = 0; /* success */
cleanup:
if (buf) free(buf);
if (f) fclose(f);
return rc;
} Section 12 of 13
Every language ships with a package manager. The depth of the ecosystem and the friction of using it varies.
| Language | Manager | Lock file | Public registry size | Typical install command |
|---|---|---|---|---|
| Java | Maven, Gradle | pom.xml, build.gradle | Maven Central, 500k+ artifacts | mvn install |
| Python | pip, poetry, uv | requirements.txt, poetry.lock, uv.lock | PyPI, 500k+ packages | pip install pkg |
| C++ | Conan, vcpkg, header-only | conanfile.txt, vcpkg.json | Conan Center, 1500+ packages | conan install . |
| C | Apt / yum / brew system packages, vendored source | None standard | OS-dependent | apt install lib-dev |
| JavaScript | npm, yarn, pnpm | package-lock.json, yarn.lock, pnpm-lock.yaml | npm, 2M+ packages | npm install pkg |
JavaScript has the largest registry but the highest dependency-tree depth (one create-react-app install pulls 1,500+ transitive packages). Python has a smaller registry but higher per-package quality on average. C++ has no canonical manager; the community is split between Conan, vcpkg, and "build from source with CMake".
Section 13 of 13
Three decision rules cover most coursework choices.
For specific course recommendations, see the data structures subject page (Java-dominated), algorithms subject page (Python-dominated), operating systems subject page (C-dominated). For language-specific help, the per-language pages walk pricing and turnaround: Java, Python, C++, C, JavaScript, Assembly.
More Resources
Time and space complexity for every common data structure and algorithm. Same operation shown across Java, Python, C++, and JavaScript so you can compare directly.
Open Big-O Cheatsheet40 errors across 5 languages, every one paired with the verbatim compiler output, root cause, and the Broken vs Fixed snippet that resolves it.
Open Common Compiler ErrorsA repeatable 5-step process for finding bugs in C, C++, Java, Python, and JavaScript. With actual GDB session output, a Valgrind trace, and a pytest reproduction template.
Open Debugging GuideFAQ
main. JEP 445 (Java 21 preview) allows unnamed classes and instance main methods so a one-file program can drop the boilerplate, but the feature is not enabled in most autograders yet. Until JEP 445 ships in LTS, the public class Main wrapper is mandatory.Cheatsheets and guides cover the general ground. For your specific brief, submit it and get expert pedagogical help within 12 hours.
Submit Assignment