12 ms·
I took a look at the gpio code, just to see what Rust for embedded would look like. I did't like the noise due obrigatory use of unwrap() after calling a funct
by childintime 9y ago
I took a look at the gpio code, just to see what Rust for embedded would look like.
I did't like the noise due obrigatory use of unwrap() after calling a function with constants (such as constructing a regex). Such setup obviously must panic when it fails.
Also, Rust seems to be missing a way to "clean out the parent scope", by saying something like:
let Some(a) = check(param0) && let Some(b) = check(param1)
else {
return Err("Illegal arguments");
}
Here 'a' and 'b' would be created in the parent scope, not in the body as in the 'if let' statement.
Note that both criticisms revolve around introducing a concept of failure in the type system. Maybe the last member of a type could correspond to "failure" by default (ie None or Err() in typical cases).
I have been recently learning Rust and like its super powers. The above observations worry me in the sense that error handling is quite central to clean and readable code, and because Rust seems to promote the nesting of the main path, which, at least to me, is an anti-pattern.
Please correct me if I'm wrong.
- Mouse47 9y agoYou're right - that would suck if you couldn't do that! In rust, damn near everything is an expression - including `if` statements. So: let a = if let Some(x) = check(param0) { x } else { return Err(""); }; Oh - I couldn't tell if you were aware by your post, but if you have a return type `T` and you want to compose it with an error type, you can use the type Result<T, ErrType>. This is functionally equivalent to having this: >Maybe the last member of a type could correspond to "failure" by default (ie None or Err() in typical cases). as a language-level feature, except it's opt-in. So functions that return `T` instead of `Result<T, _>` never return errors (besides panics, which are more-or-less 'fatal'), and that fact is obvious to the caller. That's really nice IMO.
- childintime 9y ago> let a = if let Some(x) = check(param0) { x } else { return Err(""); }; That's not DRY at all. BTW, by stating that Rust has no concept of failure, I meant to say the compiler doesn't have one, as it doesn't know that Err() in a type conveys an error. To automatically unwrap() something, I think it would have to know.
- steveklabnik 9y agoThis line is much more concise as let a = check(param0)?; or possibly let a = check(param0).map_err(|_| Err(""))?; depending.
- Mouse47 9y agoWait does that work? Unwrapping Options using `?`?
- steveklabnik 9y agoOh, I missed that it's an Option. That means that it won't work today, but https://github.com/rust-lang/rust/pull/42526 https://github.com/rust-lang/rust/pull/42526 landed, and is in beta. This means on the next release of Rust, code like this will work: fn try_result_some() -> Option<u8> { let val = Some(1)?; // Ok also works Some(val) } that is, using `?` on an Option in a function returning an Option. That being said, similar code will not yet work: fn try_result_some() -> Result<u8, Box<Error>> { let val = Some(1)?; Ok(val) } that is, using `?` on an Option in a function returning Result. This is because https://doc.rust-lang.org/nightly/std/option/struct.NoneError.html https://doc.rust-lang.org/nightly/std/option/struct.NoneErro... isn't stable yet.
- AlphaSite 9y agoI think what he is asking for is Swifts guard.
- tmzt 9y agoYou can use a tuple in that case, as in: if let (Some(a), Some(b)) = (check(param0)), check(param1)) { ... } else { ... }
- steveklabnik 9y ago> I did't like the noise due obrigatory use of unwrap() after calling a function with constants (such as constructing a regex). Such setup obviously must panic when it fails. Once we get real const evaluation, which huuuuuge steps toward were taken last week, this stuff will go from "kinda awkward" to "very good", that is, that kind of thing can run at compile time, and you'll know that the runtime code isn't calling unwrap at all. The underlying stuff here (miri) also has really interesting implications for unsafe code and tooling around it, but that's slightly further off.
- jmcomets 9y ago> which huuuuuge steps toward were taken last week I follow Rust pretty closely, but I can't wrap my finger on what you're referencing here. Got an RFC link? :)
- steveklabnik 9y agoIt's not about an RFC; it's that at the impl period days at RustFest, Oli managed to get Miri integrated into the compiler and bootstrap for the first time. https://github.com/rust-lang/rust/pull/45002 https://github.com/rust-lang/rust/pull/45002 https://github.com/rust-lang/rfcs/blob/1f5d3a9512ba08390a2226aa71a5fe9e277954fb/text/0911-const-fn.md https://github.com/rust-lang/rfcs/blob/1f5d3a9512ba08390a222... is the relevant historic RFC; still not yet stable. This work is what will enable a follow-on RFC for "real" CTFE in Rust, which in my understanding has been waiting for this to shake out. https://github.com/rust-lang/rust/pull/25609 https://github.com/rust-lang/rust/pull/25609 landed right around 1.0, two years ago, but real CTFE required waiting on MIR, which took a while to land, and then building Miri in the first place.
- kibwen 9y agoContext: MIR is an intermediate representation used by the Rust compiler; it's the final stage of Rust code before being converted to LLVM IR. Miri is an interpreter for MIR; it bypasses LLVM entirely and allows for direct execution of a certain subset of Rust (specifically the subset of code that can be evaluated at compile-time). Together this greatly expands the scope of constant evaluation in Rust code, granting Rust new metaprogramming faculties without requiring any new DSL (e.g. no need for C++-like template metaprogramming); just use the `const` keyword to run code at compile-time.