- A+

I wrote a benchmark that calculates the sum of the first 10000 primes and compared Rust to TypeScript. TS on NodeJS is the fastest among Rust, Scala, and Java. Even the programs intentionally use a functional style for testing primality aiming to show the advantages of Rust's zero-cost abstraction, NodeJS beats them all. I wonder why NodeJS, a dynamic-type-based runtime, could be such fast.

**Rust code**

`fn sum_primes(n: usize) -> u64 { let mut primes = Vec::new(); let mut current: u64 = 2; let mut sum: u64 = 0; while primes.len() < n { if primes.iter().all(|p| current % p != 0) { sum += current; primes.push(current); } current += 1; } sum } `

**TypeScript code**

`function sumPrimes(n: number): number { let primes: number[] = [] let current: number = 2 let sum: number = 0 while (primes.length < n) { if (primes.every(p => current % p != 0)) { sum += current primes.push(current) } ++current } return sum } `

The full benchmark can be found on GitHub.

The answer can't be simple because V8 does a **lot** of transformations. But here's a major point:

Node's optimizing compiler dynamically adapts the types it uses (especially for array elements). It's able to use one word integers when they fit (and *deoptimizes* the function when it receives a non fitting value).

If I take your codes as they are, the rust function takes 1.28ms to compute `sum_prime(500)`

when node takes only 1.04ms (after some warming).

But if I change the `u64`

to `u32`

in the rust code, then it only takes 608µs.

The JS code I used:

`function sum_primes(n) { var primes = []; var current = 2; var sum = 0; while (primes.length < n) { if (primes.every(function (p) { return current % p != 0; })) { sum += current; primes.push(current); } ++current; } return sum; } console.log(sum_primes(200)); // some warming for (let i=0; i<100; i++) sum_primes(100); console.time("primes"); console.log(sum_primes(500)); console.timeEnd("primes"); `

This JS code is faster than your rust code, but slower than this one:

`use std::time::Instant; fn sum_primes(n: usize) -> u32 { let mut primes = Vec::new(); let mut current: u32 = 2; let mut sum: u32 = 0; while primes.len() < n { if primes.iter().all(|p| current % p != 0) { sum += current; primes.push(current); } current += 1; } sum } fn main() { println!("{}", sum_primes(200)); let s = Instant::now(); println!("{}", sum_primes(500)); println!("duration: {:?}", s.elapsed()); } `