Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The for syntax over optional seems unnatural. I get that optional is like a list of 0 or 1 owns. Is there a fault in my reading that makes the syntax clunky?


Putting it through a for loop demonstrates that it is iterable, imo.

  template <typename T>
  void foo(const T& container) {
    for (auto value : container) {
      // process value
    }
  }

  foo(std::vector<int>())
  foo(std::optional<int>())


What seems weird here? Iterating or mapping over Options is pretty normal in functional languages.


Well, you can map over options/maybes. For-loop style iteration over an option does seem a little strange IMO, first, because syntactically it looks like overkill, and second (and more importantly), because map evals to a value, while `for` does not.

But I suppose in C++, given the centrality of looping constructs, this is what you would do to accommodate option.


You're comparing apples to oranges. In pure functional languages, Option is a fundamental type. It's a concept introduced very early on when learning FP. Historically it had the same behavior and definition.

Trying to gaslight ppl to question their reasonable reaction of std::optional transitioning from its previous behavior to an Option like behavior when no other type in C++ behaves as such is disingenuous.

Of course it is weird in the C++ context, but is it a step in the right direction? absolutely!


With syntax questions, it can help to get very concrete. There's a few different bits of syntax in this post, what is it you find clunky?


Not the person you were replying to, but

  for (auto l : logger) {
      l.log(data);
  }
bent my brain for a moment. `logger` is a list of loggers to send data do? Oh, no, it's either 0 or 1 loggers.

Rust's `if let` syntax maps much more closely to how I think about it. I guess if this becomes idiomatic C++ then it'd start looking perfectly normal to everyone, but it still seems odd. For instance, I don't think I could ever bring myself to write Python like this, even if it worked:

  def do_something(data, logger=None):
      for l in logger:
          l.log(data)


That makes sense! What's funny is, I went to go write the equivalent Rust code:

    struct Logger;
    
    impl Logger {
        fn log(&self, _: &str) {}
    }
    
    fn do_something(data: &str, logger: Option<Logger>) {
        for l in logger {
            l.log(data)
        }
    }
    
    fn main() {
        let logger = Some(Logger);
        let data = "foo";
        
        do_something(data, logger);
    }
and rustc actually warns about this:

    warning: for loop over an `Option`. This is more readably written as an `if let` statement
     --> src/main.rs:8:14
      |
    8 |     for l in logger {
      |              ^^^^^^
      |
      = note: `#[warn(for_loops_over_fallibles)]` on by default
    help: to check pattern in a loop use `while let`
      |
    8 -     for l in logger {
    8 +     while let Some(l) = logger {
      |
    help: consider using `if let` to clear intent
      |
    8 -     for l in logger {
    8 +     if let Some(l) = logger {
      |
I was actually going to say "I've never seen folks in Rust write out for loops this way, even though you can" and I suspect this lint has something to do with that!

I think this is most useful in generic contexts, I agree that I would not write this exact code this way because it does feel weird, if you know you have an Option, if let is the way to go. But if you're writing code over generic iterators, it can be nice that it exists.


> I think this is most useful in generic contexts

And to build other iterators e.g. std::iter::once is a trivial wrapper around an Option::Some.


Hah! I've internalized rustc and Clippy. Good job, team!

Yeah, I don't hate it. The semantics aren't wrong, either: an Option has 0 payload items or 1. It still feels wrong to me in ways I can't fully explain.


All true but consider writing templates/generic code, where "logger" might be a std::optional or a std::list/vector/whatever. Same syntax, different types. Pre-C++26 you'd need a specialization for std::optional, now you don't.


Fair point, but my imagination’s failing me at the moment. What kind of function would accept something where Optional makes sense and also a list/etc.?

I’m not asking to dispute. I want to be enlightened!


Anything that might accept either (0 or 1 of something) or (0 to N of something).


Yeah, outside of templates it probably makes sense just to stick to if-style syntax. It's not any more verbose than the for-loop syntax.

    if (x.has_value()) {
      doSomething(*x);
    }




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: