ExamplesBy LevelBy TopicLearning Paths
1004 Fundamental

1004 — Leap Year

Functional Programming

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

  • • Express multi-condition boolean logic with || and && and correct precedence
  • • Understand the three-case leap year rule: 400 overrides 100, which overrides 4
  • • Use Rust's u32 type for years — no negative years needed
  • • Write thorough test cases covering each branch: divisible by 400, by 100, by 4, and none
  • • Map Rust's boolean expression directly to OCaml's mod operator syntax
  • • Recognise that clean logic > branching: one expression beats if/else chain
  • Code 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

    AspectRustOCaml
    Modulo%mod
    Not equal!=<>
    Year typeu32int
    Boolean ops&&, \|\|&&, \|\|
    Return type-> boolInferred bool
    ComplexityO(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
        }
    }
    ✓ Tests Rust test suite
    #[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

  • Implement a version using a match on (year % 400, year % 100, year % 4) and compare readability.
  • Write a function leap_years_in_range(start: u32, end: u32) -> Vec<u32> using .filter(|&y| is_leap_year(y)).
  • Count how many leap years occur in the 20th century (1901–2000).
  • Implement an is_leap_year_julian(year: u32) -> bool using only the 4-year rule (no century exception).
  • In OCaml, implement next_leap_year : int -> int that finds the first leap year after the given year.
  • Open Source Repos