Java, JavaScript, Python, and C
2026-10-30
Who should prevent bugs?
| Java | JavaScript | Python | C | |
|---|---|---|---|---|
| Core approach | Write the contract down; let the compiler check it | Stay flexible; agree on conventions | Be readable and flexible; trust people to behave | Stay close to the machine; trust the programmer completely |
| Who catches a mistake? | The compiler, tests | A test, or a user | A test, a type checker, or a user | You, or a crash, or nobody |
| Java | JavaScript | Python | C | |
|---|---|---|---|---|
| Cost | Ceremony: more to write and declare | Errors surface late | Errors surface late; discipline varies by team | Memory and undefined-behaviour bugs |
| What it buys | Early feedback; tool support at scale | Speed of change; runs everywhere | Concise, readable code | Control; performance; small footprint |
Design choices explain why the same design approach looks so different.
private, final, @Override, implements._name) until #name arrived; there is still no interface, no final, no overload._name means “please do not touch”. A common Python saying is that we are all consenting adults here.| Design question | Java | JavaScript | Python | C |
|---|---|---|---|---|
| Is hiding enforced? | Yes, by the compiler | Yes for #field, by convention otherwise |
By convention | By file layout; casts can undo it |
| Is the interface written down? | Yes, required | No | Optional | By a struct you design |
| Design question | Java | JavaScript | Python | C |
|---|---|---|---|---|
| Who is trusted with memory and lifetime? | The runtime | The runtime | The runtime | You! |
| Typical failure | Does not compile | TypeError at run time |
AttributeError at run time |
Crash, or silent corruption |
| Java | JavaScript | Python | C | |
|---|---|---|---|---|
| Declare a subtype | class B extends A |
class B extends A |
class B(A) |
None; embed the base as the first member in a struct |
| Call the parent | super.method() |
super.method() |
super().method() |
Call the base function by name |
| Java | JavaScript | Python | C | |
|---|---|---|---|---|
| Mark an override | @Override (checked) |
Nothing | Nothing | Not applicable |
| Prevent overriding | final |
Nothing built in | typing.final (checker only) |
Not applicable |
| Java | JavaScript | Python | C | |
|---|---|---|---|---|
| Multiple parents | One class, many interfaces | One class (mixins by hand) | Yes, with a computed order | By embedding several structs |
| Private to the parent | private |
#field |
_field by convention |
Not visible if the struct is opaque |
super: Javaclass Employee {
private final int base;
Employee(int base) { this.base = base; }
int calculatePay() { return base; }
}
class Manager extends Employee {
private final int bonus;
Manager(int base, int bonus) {
super(base);
this.bonus = bonus;
}
@Override
int calculatePay() { return super.calculatePay() + bonus; }
}super: Python@Override makes Java’s compiler reject a method that overrides nothing (a typo). Python accepts the typo and creates a new method.
super: JavaScriptJavaScript, like Python, accepts a misspelled override as a new method.
super: Cstruct Employee {
int base;
int (*pay)(const Employee *self);
};
typedef struct {
Employee employee; /* "inherits" by embedding the base first */
int bonus;
} Manager;
static int manager_pay(const Employee *e) {
const Manager *m = (const Manager *)e;
return employee_pay(e) + m->bonus; /* the explicit super call */
}The declared type is Employee. The object is a Manager. The Manager method runs.
Java chooses overloads from the declared type, but overrides from the actual object.
JavaScript behaves like Python; C has no overloading either. Only Java makes the static type matter here.
Every language lets you build a Stack from a list, and every one lets a client bypass the stack discipline.
Substitutability: a Stack that is a List must accept everything a List accepts. If it cannot, hold the list as a field instead.

Course home · Neil Ernst ©️