Skip to content

← Orientation and the Gate step 1 of 6

Easy Primitives

One file, one function, one gate

Return twice the number you are given.

pub fn double(n: i32) -> i32

That is the whole algorithm. This first problem is not about the algorithm — it is about how you are graded here, because if you do not understand that, every later failure will look like the site being broken.

What actually gets compiled

Your submission is not compiled on its own. Three pieces of source are stuck together, in this order, and compiled as one file:

  1. your code — always first, so every line number the compiler reports is the line number you are looking at;
  2. a small JSON helper the daemon injects, so problems can take structured input;
  3. this problem’s harness, which supplies fn main(), reads a test case from standard input, calls your function, and prints the answer.

The build line is literally:

rustc -O --edition 2024 unit.rs

There is no cargo, no Cargo.toml, and no external crates at all — no serde, no tokio, no rayon, no anyhow. Everything in this course is built out of the standard library. That is a constraint, and it is also the pedagogy: when you reach async you will build the executor yourself, because there is no #[tokio::main] to hide behind.

Nothing you write is uploaded anywhere. rustc runs on your machine, through the local runtime daemon.

The three gates

A submission counts as solved only when all three of these pass:

  1. It compiles. rustc exits zero.
  2. Every test case passes, including the hidden ones.
  3. clippy -D warnings is silent on your lines.

Gate 3 is the one that surprises people, so let us be precise about it. clippy-driver -D warnings promotes every warning to an error — and that includes rustc‘s own lints, not just clippy’s. An unused variable, a needless mut, a helper function you wrote and never called: each of those is a warning, and here a warning fails you. A correct program is not automatically a passing program.

Diagnostics from the injected shim and from the harness are filtered out before you ever see them. You are never blamed for code you cannot read.

The starter is already correct — and already failing

The starter for this problem is:

pub fn double(n: i32) -> i32 {
    return n * 2;
}

It compiles. It returns the right answer for every test. It fails.

The lint is clippy::needless_return, and understanding why it exists is the first genuinely Rust-shaped idea in this course. In Rust, the last expression of a block is the value of that block. A function body is a block. So a function whose final expression is n * 2 returns n * 2 — no keyword required. return exists for leaving early, from the middle of a function; using it in the last position adds a keyword that says nothing.

Read the lint message when it fires. Clippy prints the reason and the suggested fix. That habit — reading the whole message instead of scanning for the red — is the single most valuable thing you can take out of Track 0.

Two side notes you will need later

-O means optimisations are on, which means debug_assertions is off. Integer overflow therefore wraps silently here rather than panicking. Item 1.5 is entirely about that. And #[cfg(test)] blocks are deleted before type-checking, so #[test] functions are invisible to the grader — Track 10 deals with that by having you build a test runner instead of using one.

Now delete a keyword.