7 ms·
Hello Justin Turpin! Sorry to hear your struggles with rust. It's always going to be a bit more verbose using rust than Python due to type information, but I th
by erickt 9y ago
Hello Justin Turpin! Sorry to hear your struggles with rust. It's always going to be a bit more verbose using rust than Python due to type information, but I think there are some things we could do to simplify your code. Would you be comfortable posting the 20 line code for us to review? I didn't see a link in your post.
Anyway, so some things that could make your script easier:
* for simple scripts I tend to use the `.expect` method if I plan on killing the program if there is an error. It's just like unwrap, but it will print out a custom error message. So you could write something like this to get a file:
let mut file = File::open("conf.json")
.expect("could not open file");
(Aside: I never liked the method name `expect` for this, but is too late to do anything about that now).
* next, you don't have to create a struct for serde if you don't want to. serde_derive is definitely cool and magical, but it can be too magical for one off scripts. Instead you could use serde_jaon::Value [0], which is roughly equivalent to when python's json parser would produce.
* next, serde_json has a function called from from_reader [1], which you can use to parse directly from a `Read` type. So combined with Value you would get:
let config: Value = serde::from_reader(file)
.expect("config has invalid json");
* Next you could get the config values out with some methods on Value:
let jenkins_server = config.get("jenkins_server")
.expect("jenkins_server key not in config")
.as_str()
.expect("jenkins_server key is not a string");
There might be some other things we could simplify. Just let us know how to help.
[0]: https://docs.serde.rs/serde_json/enum.Value.html https://docs.serde.rs/serde_json/enum.Value.html
[1] https://docs.serde.rs/serde_json/de/fn.from_reader.html https://docs.serde.rs/serde_json/de/fn.from_reader.html
- QuercusMax 9y agoWas the expect method supposed to be named except, as in exception? That would make a lot more sense.
- Pxtl 9y agoNot a Rust guy, but it looks like a way to say "this option value is required and if it is not present, crash with the following error". So "expect" is a fair name, since it means a value is expected and the absence of a value is unexpected. I could see "required" or "require" as a better name. Or even just break the "positive names" rule and go with "notOptional".
- eriknstr 9y agoLooking at it that way, I think it's possible to make "expect" more comfortable to read by how you phrase your error messages. Instead of let mut file = File::open("conf.json") .expect("could not open file"); and let config: Value = serde::from_reader(file) .expect("config has invalid json"); and let jenkins_server = config.get("jenkins_server") .expect("jenkins_server key not in config") .as_str() .expect("jenkins_server key is not a string"); One could write let mut file = File::open("conf.json") .expect("Need to be able to open file `conf.json'."); and let config: Value = serde::from_reader(file) .expect("The file `conf.json' must contain valid JSON."); and let jenkins_server = config.get("jenkins_server") .expect("The config must have a key named `jenkins_server'.") .as_str() .expect("The config value of `jenkins_server' must be a string."); Something like that.
- erickt 9y agoThat is a good point. I'm going to have to start being more positive in my expectations :)
- swsieber 9y agoI think it's like Assert. You pass an error message the same way you pass an error message to assert.
- erickt 9y agoIf I recall correctly we just couldn't come up with a great name for it. To me "expect" is a positive action, but the argument is about it failing to meet the expectation. Semantically I like `thing.unwrap_or(|| panic!("failure message"))`. It feels more like what I would want to say, but it just is so wordy. Ultimately I'm happy we just picked something and moved on, but still mildly annoys me whenever I write it. If only we found that perfect method name way back when...
- AlphaSite 9y agoThe java optional api uses orElseThrow which I think is quite clear.
- bluejekyll 9y agoAgreed, I've never liked 'expect' either; 'or_else_panic(msg)' would be much clearer Edit: 'or_panic(msg)' would be shorter and also good.
- erickt 9y agoI think that was one of the proposed variations, but we ended up picking the shorter .expect to cut down on repetition. We expected (ha) that this function would be used in these one-offs, so we wanted something more efficient.
- bluejekyll 9y agoAs an old Java hack, my allowance for repetition is high. Especially when using and IDE that basically writes the code for me ;)
- e12e 9y agootherwise(msg)?
- MaxGabriel 9y ago
- eriknstr 9y agoWhile it's too late to change the name "expect", could one create an alias for it and call it say, "on_error"?
- eximius 9y agoI'd expect 'on_error' to take a function as a callback, not a string. But yes, a better named function could be added
- skybrian 9y agoPerhaps or_die, similar to Perl?
- sanderjd 9y agoYep, this is what I always wanted it to be! But maybe or_panic would be better. Naming things is hard.
- eternalban 9y agoexpect[ing_error]("could not open the file")
- rootlocus 9y agoYou're not expecting an error. On the contrary, you're expecting a value or throwing an error.
- eternalban 9y agoYou're expecting specific errors.
- allan_s 9y agoor_fail_with("") ?
- IshKebab 9y ago
- GolDDranks 9y agoIf I know that the unwrap is 100% safe I tend to write: `.expect("Invariant: $REASON_WHY_THIS_NEVER_FAILS")`
- gnuvince 9y agoCool trick!
- bpicolo 9y ago4 chained function calls from config -> read a key from it is quite an ask. Though I realize there's reason for it. There are many cases I'd be happy to have panics occur for invariants. config.strictString('foo') or something of that nature seems like it could be a more ergonomic choice in cases like thise.
- bluejekyll 9y agoWhat he is showing is how someone who knows Rust well, would potentially approach this problem. What you're point out is that it's a large bar to ask a new comer to the language to do this because it requires a deeper understanding of the language to use. Is it not appropriate to show that you can reduce the complexity of a program by using other features of the language? It's not significantly different from reducing x + x + x + x To 4x
- jackcviers3 9y agoEach function call is a transformation on the previous argument. Whether or not you assign the results to a variable first before calling the second doesn't change the behavior of the code. But yes, it does appear that the config library needs an extra wrapper that loads from files and returns configs (in a context) that does the common work for you.
- huntie 9y agoIt might be easier to do: let config: HashMap<String, String> = serde_json::from_reader(file) .expect("config has invalid json"); This means that you can just do let jenkins_server = config.get("jenkins_server") .expect("jenkins_server key not in config");
- MikkoFinell 9y agoI cant even opt out of using exceptions? Good thing I didn't waste my time with this lang.
- guipsp 9y agoexpect is panic, not an exception
- caconym_ 9y agoExceptions don't exist in Rust.
- sanderjd 9y agoYou may have confused the method "expect" as being "except", as in "exception". That's not what it means - it means to "panic" with the given string as the error message. Panics in Rust have some similarities to exceptions in C++, but are not the same thing.