JavaScript, Python, Ruby and PHP are not slow because they are “interpreted”. They all compile your code before they run it. Speed comes from optimization, which happens either before the program runs or while it runs.
In fact: before optimization Python can be faster than Java, and in some cases faster than C++. C++ is faster than Java before optimizations, and after optimizations faster in some areas, slower in others. Code written to V8 can keep up with C++ on some jobs and beat Go.
We wrote one small program, an order with items, a coupon, a discount and tax, and implemented it in 11 languages, keeping the versions as close to each other as the languages allow. An optimizer can work before the program runs (static optimization, as with C++ at -O2) or while it runs (JIT optimization, as in the Java VM). The dial below changes only the JIT. The Java compiler does almost no static optimizing, so the JIT does the work. Turn it up and watch the time per call. The next two dials run the Python and C++ versions, so you can compare. All the bars use one scale.
None of this code is tweaked for performance. Each language can run faster if someone tunes the code for it. This code represents average code.
Python
JavaScript
C++ (static optimization)
C++ has no JIT. The compiler optimizes once, before the program runs, and the setting is fixed at build time.
Common objections
Isn't Python interpreted? Isn't Java interpreted until the JIT starts? Read the answers, or check our work.
Optimization is half of the story. How your data sits in memory decides the other half.
What does this mean for your code? Find out here: honestcode.software
JVM setting:
Spread:
Method: JMH, three forks of five one-second iterations, class code timed without timestamp writes. Python was measured with pyperf, ten processes of five values each, in the Ubuntu 26.04 container that ran the Java benchmarks. The first two stops are CPython 3.14.4 with PYTHON_JIT=0 and PYTHON_JIT=1. The third is PyPy 7.3.20, which implements Python 3.11, so it is a different language version from the other two. PyPy spread: class code 202 to 467 ns, functions 126 to 168 ns.
The Python code, shortened by dropping the timestamp writes, which the timed figure leaves out. The Java class follows these steps. The full source is honest-code-traces/harness/python/harness_v2.py.
class Order:
def __init__(self):
self._items = []
self._total = 0.0
self._discount = 0.0
self._tax = 0.0
self._coupon_code = ""
def add_item(self, item): self._items.append(item)
def apply_coupon(self, code): self._coupon_code = code
def calc_total(self):
total = 0.0
for i in self._items:
total += i[1]
self._total = total
def calc_discount(self):
self._discount = self._total * CouponRegistry.get_instance().lookup(self._coupon_code)
def calc_tax(self):
self._tax = TaxService.get_instance().calculate("NY", self._total - self._discount)
def grand_total(self):
return self._total - self._discount + self._tax
def dishonest_scenario(items):
order = Order()
for it in items:
order.add_item(it)
order.apply_coupon("SAVE10")
order.calc_total()
order.calc_discount()
order.calc_tax()
return order.grand_total()
JavaScript: the TypeScript version of the program, run with tsx on Node 22 (V8) and timed with mitata, one process per setting, so there is no spread figure. The stops are --jitless, --no-opt and the default flags.
Go: the page has no Go dial. In the 11-language harness, Go (go test with b.Loop) takes 311 ns on the class code and 43 ns on the plain functions. JavaScript on V8 takes 124 ns and 99 ns, so V8 is about 2.5 times faster on the class code and about 2.3 times slower on the plain functions.
C++: g++ in the container that ran the Java benchmarks, Google Benchmark, five repetitions, one level per build (-O0 to -O3). The class code is slower at -O3 than at -O2, and the page reports it as measured.
Allocation: with the full JIT the class version allocates about 0 bytes per call and the plain functions 56. With escape analysis off they allocate 176 and 200.
What HotSpot did: with the full JIT it compiled the 15 steps into one method and inlined every Order call. Raw log: honest-code-traces/measured/optimizer-dial/inlining/inlining.log.