1004 — Leap Year
Tutorial Video
Text description (accessibility)
This video demonstrates the "1004 — Leap Year" functional Rust example. Difficulty level: Fundamental. Key concepts covered: Functional Programming. Determine whether a year is a leap year using the Gregorian calendar rules: divisible by 400, OR divisible by 4 but not 100. Key difference from OCaml: | Aspect | Rust | OCaml |
Tutorial
The Problem
Determine whether a year is a leap year using the Gregorian calendar rules: divisible by 400, OR divisible by 4 but not 100. Implement the single boolean expression (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0) and verify it on edge cases (2000, 1900, 2004, 2100). Compare with OCaml's equivalent.
🎯 Learning Outcomes
|| and && and correct precedenceu32 type for years — no negative years neededmod operator syntaxCode Example
#![allow(clippy::all)]
/// Idiomatic Rust: Direct boolean logic with clearest precedence
pub fn is_leap_year(year: u32) -> bool {
(year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_divisible_by_400() {
assert!(is_leap_year(2000));
assert!(is_leap_year(1600));
}
#[test]
fn test_divisible_by_100_but_not_400() {
assert!(!is_leap_year(1900));
assert!(!is_leap_year(1800));
}
#[test]
fn test_divisible_by_4_but_not_100() {
assert!(is_leap_year(2004));
assert!(is_leap_year(2024));
}
#[test]
fn test_not_divisible_by_4() {
assert!(!is_leap_year(2001));
assert!(!is_leap_year(2003));
assert!(!is_leap_year(2100));
}
#[test]
fn test_edge_cases() {
assert!(is_leap_year(4)); // Year 4 is a leap year
assert!(!is_leap_year(2)); // Year 2 is NOT a leap year
}
}Key Differences
| Aspect | Rust | OCaml |
|---|---|---|
| Modulo | % | mod |
| Not equal | != | <> |
| Year type | u32 | int |
| Boolean ops | &&, \|\| | &&, \|\| |
| Return type | -> bool | Inferred bool |
| Complexity | O(1) | O(1) |
This example demonstrates that some algorithms are language-independent at the semantic level — only the syntax changes. The key skill is recognising the three-tier hierarchy in the leap year rule and expressing it as a single minimal boolean formula.
OCaml Approach
OCaml's let leap_year year = (year mod 400 = 0) || (year mod 4 = 0 && year mod 100 <> 0) is structurally identical. The mod operator corresponds to %; <> corresponds to !=. The logic and precedence rules are the same. This is one of the simplest cross-language comparisons: the two implementations differ only in surface syntax.
Full Source
#![allow(clippy::all)]
/// Idiomatic Rust: Direct boolean logic with clearest precedence
pub fn is_leap_year(year: u32) -> bool {
(year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_divisible_by_400() {
assert!(is_leap_year(2000));
assert!(is_leap_year(1600));
}
#[test]
fn test_divisible_by_100_but_not_400() {
assert!(!is_leap_year(1900));
assert!(!is_leap_year(1800));
}
#[test]
fn test_divisible_by_4_but_not_100() {
assert!(is_leap_year(2004));
assert!(is_leap_year(2024));
}
#[test]
fn test_not_divisible_by_4() {
assert!(!is_leap_year(2001));
assert!(!is_leap_year(2003));
assert!(!is_leap_year(2100));
}
#[test]
fn test_edge_cases() {
assert!(is_leap_year(4)); // Year 4 is a leap year
assert!(!is_leap_year(2)); // Year 2 is NOT a leap year
}
}#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_divisible_by_400() {
assert!(is_leap_year(2000));
assert!(is_leap_year(1600));
}
#[test]
fn test_divisible_by_100_but_not_400() {
assert!(!is_leap_year(1900));
assert!(!is_leap_year(1800));
}
#[test]
fn test_divisible_by_4_but_not_100() {
assert!(is_leap_year(2004));
assert!(is_leap_year(2024));
}
#[test]
fn test_not_divisible_by_4() {
assert!(!is_leap_year(2001));
assert!(!is_leap_year(2003));
assert!(!is_leap_year(2100));
}
#[test]
fn test_edge_cases() {
assert!(is_leap_year(4)); // Year 4 is a leap year
assert!(!is_leap_year(2)); // Year 2 is NOT a leap year
}
}
Exercises
match on (year % 400, year % 100, year % 4) and compare readability.leap_years_in_range(start: u32, end: u32) -> Vec<u32> using .filter(|&y| is_leap_year(y)).is_leap_year_julian(year: u32) -> bool using only the 4-year rule (no century exception).next_leap_year : int -> int that finds the first leap year after the given year.