• 3 Posts
  • 7 Comments
Joined 7 months ago
cake
Cake day: July 2nd, 2025

help-circle
  • Not very familiar with the libraries, and BB_C has already given a lot of more detailed feedback, but here are some small things:

    • Even without rewriting get_files_in_dir as a single chain of method calls, you can still replace
      if dir.is_err() {  
          return None  
      };
      // use dir.unwrap()
      
      with
      let Ok(dir) = dir else {
          return None;
      };
      // use dir
      
      In general, if you can use if let or let else to pattern match, prefer that over unwrapping – Clippy has a lint relating to this, actually.
    • Although the formatting doesn’t seem horrible, it doesn’t seem like Rustfmt was used on it. You might want to make use of it for slightly more consistent formatting. I mainly noticed the lack of trailing commas, and the lack of semicolons after return None in get_files_in_dir.


  • There was a recent langdev Stack Exchange question about this very topic. It’s a bit trickier to design than it might seem at first.

    Suppose we require a keyword – say var – before all binding patterns. This results in having to write things like
    for (&(var x1, var y1, var z1), &(var x2, var y2, var z2)) in points.iter().tuple_windows() {},
    which is quite a bit more verbose than the current
    for (&(x1, y1, z1), &(x2, y2, z2)) in points.iter().tuple_windows() {}.
    Not to mention you’ll have to write let var x = 0; just to declare a variable, unless you redesign the language to allow you to just write var x = 0 (and if you do that, you’ll also have to somehow support a coherent way to express if let Some(x) = arr.pop() {} and let Some(x) = arr.pop() else {todo!()}).

    Suppose we require a keyword – say const – before all value-matching patterns that look like variables. Then, what’s currently

    match (left.next(), right.next()) {
        (Some(l), Some(r)) => {}
        (Some(l), None) => {}
        (None, Some(r)) => {}
        (None, None) => {}
    }
    

    turns into either the inconsistently ugly

    match (left.next(), right.next()) {
        (Some(l), Some(r)) => {}
        (Some(l), const None) => {}
        (const None, Some(r)) => {}
        (const None, const None) => {}
    }
    

    or the even more verbose

    match (left.next(), right.next()) {
        (const Some(l), const Some(r)) => {}
        (const Some(l), const None) => {}
        (const None, const Some(r)) => {}
        (const None, const None) => {}
    }
    

    and you always run the risk of forgetting a const and accidentally binding a new match-all variable named None – the main footgun that syntactically distinguishing binding and value-matching patterns was meant to avoid in the first place.

    Suppose we require a sigil such as $ before one type of pattern. Probably the best solution in my opinion, but that’s one symbol that can no longer be used for other things in a pattern context. Also, if you’re already using sigils before variable names for other purposes (I’ve been sketching out a language where a pointer variable $x can be auto-dereferenced by writing x), doubling up is really unpleasant.

    …So I can understand why Rust chose to give the same, most concise possible syntax for both binding and value-matching patterns. At least compiler warnings (unused, non-snake-case variables) are there to provide some protection from accidentally turning one into the other.







  • Can’t resist pointing out how you should actually write the function in a “real” scenario (but still not handling errors properly), in case anyone wants to know.

    If the list is guaranteed to have exactly two elements:

    fn is_second_num_positive_exact(input: &str) -> bool {
        let (_, n) = input.split_once(',').unwrap();
        n.parse::<i32>().unwrap() > 0
    }
    

    If you want to test the last element:

    fn is_last_num_positive(input: &str) -> bool {
        let n = input.split(',').next_back().unwrap();
        n.parse::<i32>().unwrap() > 0
    }
    

    If you want to test the 2nd (1-indexed) element:

    fn is_second_num_positive(input: &str) -> bool {
        let n = input.split(',').nth(1).unwrap();
        n.parse::<i32>().unwrap() > 0
    }