Type Ceremony
What fraction of your code is boilerplate rather than logic?
Ceremony ratio = ceremony lines / total lines. Ceremony lines are imports, package declarations, main wrappers, lone closing braces, and type-only annotation lines. Lower means more of your code does actual work.
Ceremony by Language
Averaged across 7 benchmark problems.
| Language ↕ | Ceremony Ratio ↑ | Ceremony Lines ↕ | Total Lines ↕ |
|---|---|---|---|
| Clojure | ★0▼ | ★0▼ | ★8▼ |
| Erlang | ★0▼ | ★0▼ | ★12▼ |
| Python | ★0.105▼ | ★1.7▼ | ★14.6▼ |
| Elixir | ★0.147▼ | ★2.6▼ | ★17.4▼ |
| Zig | ★0.195▼ | ★7.1▼ | ★39.9▼ |
| Objective-C | ★0.214▼ | ★3▼ | ★14▼ |
| Haskell | ★0.221▼ | ★5▼ | ★21.9▼ |
| JavaScript | ★0.222▼ | ★3.1▼ | ★15.7▼ |
| Ruby | ★0.224▼ | ★3.1▼ | ★14.3▼ |
| TypeScript | ★0.229▼ | ★3.4▼ | ★15.9▼ |
| Swift | ★0.27▼ | ★6▼ | ★22.3▼ |
| Kotlin | ★0.284▼ | ★5.9▼ | ★19.7▼ |
| Go | ★0.31▼ | ★8.1▼ | ★26.6▼ |
| Milo | ★0.313▼ | ★8.3▼ | ★26.9▼ |
| Rust | ★0.317▼ | ★7.1▼ | ★22.6▼ |
| C | ★0.326▼ | ★11.7▼ | ★39.7▼ |
| C++ | ★0.348▼ | ★9.6▼ | ★27.9▼ |
| Java | ★0.397▼ | ★10.3▼ | ★26.6▼ |
| C# | ★0.438▼ | ★7▼ | ★16▼ |
What drives the differences?
Python (10%) — no imports for builtins, no main wrapper, no braces. Almost every line is logic.
Java (40%) — package declarations, class wrappers, public static void main, import statements, closing braces. Nearly half the code is scaffolding.
Rust (32%) vs Zig (20%) — Rust's use imports, fn main(), and match arm braces add up. Zig's @import is terser and comptime reduces boilerplate.
Go (31%) — package main, import, func main(), explicit if err != nil blocks. Error handling is ceremony by design — Go chose explicitness over conciseness.
TypeScript (23%) vs JavaScript (22%) — nearly identical. Type annotations don't count as ceremony since they carry semantic weight. The difference is mainly import style.
What counts as ceremony?
Lines classified as ceremony:
- Imports/includes —
import,require,use,#include - Package/module declarations —
package main,module X - Entry point wrappers —
public static void main,fn main() - Lone closing delimiters —
},end,) - Type-only lines — lines that exist solely for type annotations with no logic
Lines NOT counted as ceremony:
- Function signatures (they define behavior)
- Variable declarations with initialization
- Type annotations inline with logic
- Comments
The formal basis
Ore et al. (ASE 2018) coined "Type Annotation Burden" and found: developers average 136 seconds per correct annotation and get it right only 51% of the time.
Annotations are expensive. Our ceremony metric captures the broader category — all structural lines that exist for the compiler rather than for expressing intent.