3 ms·
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?
by DSingularity 1y ago
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?
- steveklabnik 1y agoWith 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?
- kstrauser 1y agoNot 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)
- steveklabnik 1y agoThat 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.
- masklinn 1y ago> 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.
- kstrauser 1y agoHah! 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.
- PaulDavisThe1st 1y agoAll 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.
- kstrauser 1y agoFair 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!
- PaulDavisThe1st 1y agoAnything that might accept either (0 or 1 of something) or (0 to N of something).
- mkehrt 1y agoWhat seems weird here? Iterating or mapping over Options is pretty normal in functional languages.
- deleted 1y ago[deleted]
- lo_zamoyski 1y agoWell, 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.
- halayli 1y agoYou'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!
- lanyard-textile 1y agoPutting 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>())
- loeg 1y agoYeah, 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); }