17 ms·
Announcing Rust 1.13
- Perceptes 10y agoCongrats to the team and thank you! As always, my Docker image for Rust has been updated for 1.13: https://hub.docker.com/r/jimmycuadra/rust/ https://hub.docker.com/r/jimmycuadra/rust/
- Scaevolus 10y agoThe ? operator looks lovely. It's like the C# null conditional operator, but for the Result pattern: try!(try!(try!(foo()).bar()).baz()) Becomes foo()?.bar()?.baz()? Versus the Go equivalent: a, err := foo() if err != nil { return nil, err } b, err := a.bar() if err != nil { return nil, err } c, err := b.baz() if err != nil { return nil, err } return c
- JoshTriplett 10y agoExactly. It isn't just that it's shorter; it fixes a right-left-right-left alternating reading order, turning it into a left-to-right reading order.
- Scaevolus 10y agoI think it also lets you turn this: try!(baz(try!(bar(try!(foo()))) into baz(bar(foo()?)?)? Which isn't as bad as the alternating order for chained evaluation, but cleans up a lot of the noise.
- JoshTriplett 10y agoTrue, though in some cases you may want to write that one as: foo().and_then(bar).and_then(baz) That becomes a bit more verbose, but it reads left-to-right, and works better if you want to use a closure as one of the functions. Which form looks more readable in a given circumstance may depend on the nature of foo, bar, and baz.
- masklinn 10y agoIt has somewhat different semantics though, for instance with `?` all three functions can use different error types.
- richardwhiuk 10y agoThey have to be convertable though, because the function must have a single result code.
- lisivka 10y agoWhat if I want to do something like in following snipet: baz(foo)?("Cannot do baz, foo={}", foo).bar()?"Cannot do bar"; Is there a syntax sugar for such thing? If so, I will be converted to Rust.
- steveklabnik 10y agoIt would work with just the ?s if you had the right implementations of the error conversion functions. I have an example below.
- lisivka 10y agoCompiler cannot determine intent, so it will not be able to produce correct, user readable error message, in user language.
- steveklabnik 10y agoYes, that's why you end up writing an error type and the conversions between various errors.
- lisivka 10y agoImagine, you are taking exam. If you found incorrect question in exam, then it is a bug. If you answered all questions but wrongly, then it is a failure. If you answered correctly to all answers but examiner said that you failed, then it is an error. In case of bug, code must panic. In case of failure, code must return a result, which clearly says that this is the failure. Try next time. In case of error, code must print informative description of error, bunch of data, and maybe some hints to operator, so he will be able to fix it. We are talking about errors, right? Why I need conversions to display bunch of strings with descriptions and variables to an operator? Just let me collect strings and print them to a log.
- steveklabnik 10y ago
- bluetech 10y agoHas anyone suggested some sort of postfix macro syntax? I don't have one in mind, but perhaps there is some nice looking, viable one. That might have been a more general solution than a new operator.
- JoshTriplett 10y ago> Has anyone suggested some sort of postfix macro syntax? Yes, numerous people. A few different discussions have gone by; it has many potential applications, but it introduces several aspects of syntactic weirdness and parsing weirdness, so it'd require a lot of care to introduce if at all.
- zalmoxes 10y agoAs a Go developer, I'm curious how is the error handled when foo() or bar() fail? Could you show an example where `bar()` returns a re-triable error or a fatal error etc? something where I have to make a decision other than returning it up the call stack?.
- Dobbs 10y ago`try!(foo)` is roughly equivalent to this (invalid) code: foo().unwrap_or_else({ |e| return Err(e) }) Or in Go terms: a := try!(foo) is equivalent to: a, err := foo() if err != nil { return nil, err } Basically it will take the result of foo, and if foo returns an error it will return the error itself. https://doc.rust-lang.org/beta/std/result/ https://doc.rust-lang.org/beta/std/result/ has lots of examples of alternative ways you can deal with the error case, or the Ok() case of a result.
- zphds 10y agoIt's worth mentioning that try! is a macro that basically takes that expr and turns it to something similar to your go example.
- steveklabnik 10y agoWhen they fail, it's like "return err"; that is, they just return the error value. You can only make it return up the call stack, that's it. It's for recoverable errors, not fatal ones. And the calling function would check for the error case and re-try if that's the behavior it wants.
- tsuraan 10y agoSo do all the functions have to have the same error type as the function that is calling them? I don't know rust, but in haskell notation, if a function returns "Either x y" would it then only be able to use the "?" notation on functions that themselves return "Either x z", and not on functions that return "Either a b" (so, failure sides have to match, but success sides are flexible)? EDIT: Answering my own question: https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md https://github.com/rust-lang/rfcs/blob/master/text/0243-trai... makes it pretty clear; the error types must be the same. Which completely makes sense.
- bresc 10y agoi actually don't think the Go version is bad. I can very clearly see what is happening and I can also do something with the error
- vvanders 10y agoNothing keeping you from using the same approach(or even some of the really nice mapping functions), it just lets you get rid of the boilerplate that you see there when you want to.
- zalmoxes 10y agoThe difference is that if I thought the Go style is easier to read/debug I couldn't prevent you from writing it in the complex one-liner way. The go way is a little more verbose/uglier but we are both going to do it in the same way as will the 30 other developers working on the project.
- Etzos 10y agoI don't think it's fair to say that the option Rust gives you is more complex. It's a syntactic convenience which reduces the chance of a someone typing a mistake in the longer form. Regardless of how simple the language, there is always more than one way to do things. Rust is just giving you the choice to eliminate a lot of boilerplate if you so desire. In reality most Go users will opt to use the style mentioned above instead of something more verbose/complex and most Rust users will likely opt for the new ? operator.
- cpuguy83 10y agoThe only thing bad about Go's version (other than the usual repetitive code complaints) is it's easy to ignore (ie forget) to handle an error. And really much of the error handling in Go is by convention (ie, `if err != nil { return nil, err }`) rather than actual language semantics. Honestly it would be nice to be able to always return the error (without special macros or symbols) if there is one unless I've explicitly setup a handler block.
- namelezz 10y agoI find the Go version to be easier to debug though.
- junke 10y agoI hope so, because it is more subject to accidental copy-paste bugs.
- pcwalton 10y agoWhy? Can you explicitly name a type of mistake that might happen and explain how Go solves it in a way that Rust does not?
- namelezz 10y agoIt's not really a mistake. Just coding preference. For example: do_A()?.do_B()?.do_C()?. With the one line statement like that, when weird things show up, I don't really know if it's caused by bugs in do_A, do_B, or do_C. The linear layout of Go code lets me go through each do_X call line by line and setting break points is also easier. The problem here is when I need to investigate the chain do_A()?.do_B()?.do_C()?., I may have to rewrite that statement.
- pcwalton 10y agoI agree that we should have good debugging tools for this (in particular, break on error return). But note that you can break on function calls and use "finish" to effectively go call by call to see where the error is today.
- globalgobble 10y agoThank you for showing the "simple is beautiful" in favor of GO.
- moomin 10y agoThat's because they're both >>= in Haskell. So is SelectMany in C#. Or to put it another way, it's taking an operation that does this: a -> t of b And turns it into one that does this: t of a -> t of b There's a formal name for "t"s that support this operation. I'll let you guess what it is. :)
- tatterdemalion 10y agoThis is inaccurate. While Result is a monad, `?` in Rust is not the monadic bind. That's the `and_then` method.
- deleted 10y ago[deleted]
- lomnakkus 10y agoWhile it may be convenient, it's truly worrying such (EDIT: was "many") syntactic special cases are going into Rust at this point. (It may be the case that these things absolutely cannot be handled in a systematic way in a no-GC/no-runtime language, but I'd really like to see some evidence that this is the case.)
- steveklabnik 10y agoWhich ones specifically worry you? I can't think of many, but I am also incredibly biased.
- lomnakkus 10y agoSorry, phrasing was bad. I've edited.
- steveklabnik 10y agoNo worries, it happens. What worries you about it? What things need to be "handled in a systematic way"? Are you just generally opposed to any new syntax in languages or something?
- lomnakkus 10y agoSee my other comment; https://news.ycombinator.com/item?id=12924880 https://news.ycombinator.com/item?id=12924880
- Manishearth 10y ago> how many I can only think of one redundant feature, and that is the ? operator. This is because `try!` gets used very often in in a lot of code. I can only think of one syntactic feature (redundant or otherwise) that doesn't get used often and that is HRTB(`for<'a>`), which needs to be there to be able to specify some types correctly (but is very rare).
- 10y ago
- QuantumLogic 10y agoI don't get why they'll let the language be abstracted in that way, but are against having ternary operators. It's the one thing that's somewhat bugged me about Rust. Aside from this one minor thing, I"ve been really loving the language itself. let greater = a < b ? b : a; Is a lot better than having to write this all the time: let greater = if a < b { return a; } else { return b; };
- steveklabnik 10y agoThis doesn't duplicate anything in the language; it moves a stdlib macro to be included in the core language. Since if is an expression, ternay operators would be wholly redundant.
- QuantumLogic 10y agoThe whole point of it would be to have a higher level of abstraction which makes codebases more concise. Avoiding duplication for the sake of avoiding it is as nonsensical as avoiding 100 dollar bills since we already have 100 single dollar bills that could make it up.
- masklinn 10y ago> The whole point of it would be to have a higher level of abstraction What are you talking about? A ternary isn't a higher level of abstraction, it's at best the exact same thing with a different syntax, at worst it's a more limited version of the same.
- masklinn 10y agoBut…. these are two completely different statements, the equivalent Rust is if a < b { b } else { a } why are you adding sprurious returns? And if you need to get the minimum of two values so much that actually impacts you, write a `min!` macro?
- shepmaster 10y ago
- Animats 10y agoVersus the Python equivalent: try: foo().bar().baz() except Exception as message: return message
- prirun 10y agoI think the Python equivalent is just: foo().bar().baz() ie, let someone higher up the stack handle the error.
- paulddraper 10y agoIt's true. Rust doesn't have exceptions, for many reasons. One is non-locality of exceptions. Even gotos but bounded by a function. Exceptions, however...those can take you anywhere. But the other side, as you point out, is that exception many common patterns are much made more succient.
- Arnavion 10y ago>One is non-locality of exceptions. Even gotos but bounded by a function. Exceptions, however...those can take you anywhere. I've never understood this argument. Where does `try!()` take you if there's an error? To the caller. If the caller also has a `try!()`, where does that take you? To the caller's caller. Where does `throw new FooException()` take you? To the caller. If the caller doesn't have a `catch(FooException)`, where does that take you? To the caller's caller. Edit: Note to commenters: I'm not arguing about explicit vs implicit returns. I do agree that explicit returns are nicer to read and reduce the surface area of a language. My comment is solely for the "Exceptions can take you anywhere" sentiment.
- Manishearth 10y agoExplicit vs implicit basically. You don't get to ignore the error. If the caller does have a try, it propagates. If the caller doesn't have a catch, it propagates. This becomes important because now your code no longer has invisible escape hatches 20 levels deep. You design your function with specific points where it may stop executing. You control when your function returns. You can also store the error value and handle it later (Servo makes use of this pattern often -- e.g. a network request with a body of Err, which needs to be handled when we try to read the body). > Where does `try!()` take you if there's an error? To the caller. If the caller also has a `try!()`, where does that take you? To the caller's caller. You can say this about return, too. returns and try both take you to the caller. The caller then bubbles you up, because it explicitly returns or tries.
- iand 10y agoHow do you decorate the errors? In Go I might write a, err := foo() if err != nil { return nil, fmt.Errorf("failed to foo: %v", err) }
- beefsack 10y agoIf you want something like this, you'd usually use your own error type to wrap the errors returned from the functions you call. You can implicitly do the conversions and keep the code the same if you implement `From` or `Into` for the wrapped error type.
- ameliaquining 10y agoYou often won't need to change the error object from what foo() returns; Rust errors are generally structs or enums, rather than non-machine-readable strings. But if you do need to change it, it looks like this: foo().map_err(MyError::new)?
- cpuguy83 10y agogo errors are generally backed by structs as well (though not necessarily), even `fmt.Errorf("some error")` is a struct (called `errorString`). `Error() string` is just the interface that things that want to be errors must implement, which ideally gives you the human readable version of the error.
- saghm 10y agoIn Rust, I think it's more idiomatic to just implement the `Display` trait on you error type so that you can generate the string when you need it instead of at the time the error occurs
- dasfasf 10y agoI use error_chain let a = foo().chain_err(|| "failed to foo")?;
- masklinn 10y ago`?` will convert the original error to the one the caller returns so you can implement the decoration in the conversion if that's suitable, otherwise `Result#map_err` lets you convert an error "at the callsite" (and is a noop if there was no error). Alternatively, you can use error_chain: https://brson.github.io/error-chain/error_chain/index.html https://brson.github.io/error-chain/error_chain/index.html.
- hnakamur 10y agoIn Go, I use https://github.com/pkg/errors https://github.com/pkg/errors these days and wrap errors with stack trace. package main import ( "fmt" "io" "os" "github.com/pkg/errors" ) func main() { v, err := run() if err != nil { fmt.Printf("err=%+v\n", err) os.Exit(1) } fmt.Printf("v=%d\n", v) } func run() (*int, error) { a, err := foo() if err != nil { return nil, errors.WithStack(err) } b, err := a.bar() if err != nil { return nil, errors.WithStack(err) } c, err := b.baz() if err != nil { return nil, errors.WithStack(err) } return c, nil } func foo() (*a, error) { return new(a), nil } type a struct{} func (a *a) bar() (*b, error) { return new(b), nil } type b struct{} func (b *b) baz() (*int, error) { return nil, io.EOF // some arbitrary error for demo } This prints a useful stack trace like below and you can know where the error occurred. $ go run main.go err=EOF main.run /home/hnakamur/go/src/bitbucket.org/hnakamur/stacktrace-demo/main.go:31 main.main /home/hnakamur/go/src/bitbucket.org/hnakamur/stacktrace-demo/main.go:12 runtime.main /usr/local/go/src/runtime/proc.go:183 runtime.goexit /usr/local/go/src/runtime/asm_amd64.s:2086 exit status 1
- jstimpfle 10y agoThis is superficially nice, but let's not forget that we would hardly do this in practice. It's much more likely that we would write your Go version with some error handling or logging messages added in. Practical concerns aside, in Haskell you get these things from the Maybe monad without extra syntax or macros: foo >>= bar >>= baz
- webkike 10y agoI'm pretty sure that ">>=" is "extra syntax". The only difference is in Haskell any function with two arguments can be interpreted as infix.
- jstimpfle 10y agoIt's not built-in syntax, not even a macro. Just a binary function.
- saghm 10y agoI think this would actually be more comparable to the Either monad. Also, "without extra syntax or macros" is kind of a trivial distinction, as `>>=` is just a function, not some sort of magic. That being said, I really wish there were some sort of equivalent of `try` or `?` for options in Rust. I don't feel like I want monads in Rust in general, but when dealing with options, I definitely miss the Maybe monad.
- jstimpfle 10y ago"extra syntax or macros" refers to OP's example of "?". That ">>=" is not magic is exactly what I said (meant to say).
- saghm 10y agoI guess I'm not seeing why having a function rather than a macro is really that much of a distinction in this case. Either way, it's essentially just a namespaced block of code that compiles down to an AST fragment; I don't think the facts that one of them uses the stack and that they're compiled at slightly different times really make much of a difference here.
- sudeepj 10y agoI think the new operator works only with Result. Had it been for Option also, it would have been awesome.
- steveklabnik 10y agoIt can be extended for Option in the future, we're just not sure that we're doing it yet. (I personally am opposed, but I suspect I'm in the minority.)
- imtringued 10y agoWrite a function to turn Option into a Result.
- amatheus 10y agoRust looks great, I'm not using it but learning and it look fantastic. I have one question, I guess off-topic: Rust uses LLVM, like Swift, Julia etc. Could these LLVM languages interoperate better because of this common foundation? Maybe link using LLVM IR instead of C ABI FFI, or something like that?
- muizelaar 10y agoNot obviously. For example, all of those languages mangle names differently.
- TD-Linux 10y agoThe LLVM IR doesn't define an ABI - in particular, most of the ABI is already "burned in" at the point where LLVM IR exists.
- Retra 10y agoLLVM has so many little ways to configure its output, and unless two LLVM users configure the outputs to be compatible, they are unlikely to be. LLVM is more of a toolset with some language than a shared infrastructure.
- the_duke 10y agoIt's astonishing that, in just 6 weeks 155 people contributed. (1.12 was September 29th) Rust sure seems to draw a lot of enthusiasm.
- OJFord 10y agoThey didn't necessarily actually contribute in that time though, presumably the list is of people who's contributions were merged into the release branch (or master during that timeframe, or... according to whatever workflow they're using). Not to detract from your point though. It's an awesome language, I'm just learning it but enthusiastically so for sure!
- Manishearth 10y agoI think it's the contributions merged in master that are in the 1.13 release but not 1.12. However, the timeframe for that is the same -- it is a different period of 6 weeks, but still a 6 week period.
- OJFord 10y agoWhy is it a 6 week period? Someone could open a PR today and not see it merged for a year, surely?
- steveklabnik 10y agoThe Rust release cycle is six weeks. They could, but this counts people who have landed a patch, not opened a PR. That many people got a patch into this release.
- OJFord 10y agoMy point is just that they may have produced the patch outside of the six week period. When it makes the release is somewhat arbitrary, and out of the contributor's control. Regardless, as I said below, it's great that so many people are contributing whatever the time frame :)
- shmerl 10y agoHow far along is the effort for efficient code reuse (such as filling the gaps of lack of inheritance)? I.e. this: * https://github.com/rust-lang/rfcs/issues/349 https://github.com/rust-lang/rfcs/issues/349 * https://github.com/rust-lang/rust/issues/31844 https://github.com/rust-lang/rust/issues/31844 Is it something coming soon, or it's pretty far still?
- steveklabnik 10y agoSpecialization would only be one piece of the puzzle, and as you can see, it's not in stable yet. All of the bits are still too far out to give a good estimate of.
- shmerl 10y agoThanks. Do you expect that to introduce some non backward compatible changes to language (and for example require a new major version)?
- steveklabnik 10y agoI do not, no, and I would suspect that it'd be a non-starter if it did require it.
- shmerl 10y agoGreat, thanks!
- nercury 10y agoInitial work on specialization has already landed on nightly and is backwards compatible. AFAIK, there are no plans to break that.
- shmerl 10y agoThat's good!
- sametmax 10y agoIsn't that only necessary because rust doesn't have exceptions ?
- steveklabnik 10y agoIn some sense, yes. But in another sense, not everyone agrees that exceptions are a good idea, and so would prefer this even if we did.
- Gankro 10y agoIt's all the same stuff, man. Rust just: * makes you be explicit about call sites which throw * makes it easy to reify fallible computation (so it can be stored in e.g. a Future) For instance: fn foo() -> Result<Value, IoError> { let x = a()?; let _ = b(); if someCondition { return Err(IoError::Whatever) } return c(x).unwrap(); } is just Value foo() throws IOException { x = a(); try { b(); } catch(Exception e) { /* TODO: ERROR HANDLING? */ } if (someCondition) { throw new IOException(); } try { return c(x); } catch(Exception e) { abort(); } } This is made especially clear by Swift's model which is pretty much exactly the same as Rust's, but makes it look like exceptions: // RIP typed errors func foo() -> Value throws { let x = try a() // "rethrow" try? b() if someCondition { throw "Oh No IO!" } return try! c(x) }
- steveklabnik 10y agoYou're forgetting about language pads and shenanigans.
- Gankro 10y agoUnwinding is an implementation of exceptions. You can implement them as returns, or, in the case of Swift, passing in a pointer for the Error type.
- 10y ago
- Animats 10y agoWell, it's concise. The main problem is that the error action is "return" - you have to bail out of the entire function. What happens if you use "?" within a lambda? Does it bail out of just the lambda, or the entire function? What about nested functions? (Can you have a named nested function which can access its outer scope? This StackOverflow post [1] says no, but may be wrong or obsolete.) If this works with nested block structure, it's more useful. Having a "match" for Err/Some around a lambda with with lots of "?" clauses would be useful. That provides a way to get the error from some complicated chain without leaving the function. [1] http://stackoverflow.com/questions/26685666/a-local-function-in-rust http://stackoverflow.com/questions/26685666/a-local-function...
- wyager 10y agoThe answer seems obvious; it's the same behavior "return" has, i.e. it returns from the function it's currently in, not something a few levels up.
- steveklabnik 10y agoIt might seem obvious, but Ruby, for example: def lambda_test lam = lambda { return } lam.call puts "Hello world" end This will print "hello world". But this: def proc_test proc = Proc.new { return } proc.call puts "Hello world" end Will print nothing, as the 'return' returns from proc_test. Examples taken from here: http://awaxman11.github.io/blog/2013/08/05/what-is-the-difference-between-a-block/ http://awaxman11.github.io/blog/2013/08/05/what-is-the-diffe...
- wyager 10y agoWow, that's a pretty nonsensical semantic. Thankfully, Rust is fairly sensible.
- Rusky 10y agoIt gets used most to enable returning from the outer function while within loop-body-like procs. Rust iterators used to be like that too (pre-1.0), but they switched to the current style to get rid of that complexity.
- randyrand 10y agoCan someone explain to me why rust decided not to support pattern matching with different types? Suchas: let x = Bus(); match x{ Car => ... Bus => ... Person => ... } You would need to have runtime type information of course, this could be a compiler flag.
- elihu 10y agoBecause rust is statically typed, and "x" has to have a concrete type known at compile time? Maybe there's a use case for matching trait objects against types to get back the original type. But, I think you could do the same thing by adding a trait method that returns Option<T> for some desired type T. If the object wasn't that type, it could just return None.
- tatterdemalion 10y agoAnd this is actually implemented by the Any trait. https://doc.rust-lang.org/std/any/trait.Any.html https://doc.rust-lang.org/std/any/trait.Any.html
- Manishearth 10y agohttps://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref https://doc.rust-lang.org/std/any/trait.Any.html#method.down... ? :)
- stouset 10y agoWhy can't you already do this with an enum? Rust isn't go. You don't have to break out of the type system because it doesn't have generics.
- Manishearth 10y agoRust has static types with generics and algebraic data types. 99% of the use cases for that get covered. It has trait objects for when you need runtime type information, but they're used very rarely and you can make that pattern work with a chain of `downcast_ref` if lets or obviate its need by implementing methods.
- tmaly 10y agoI am thinking about learning Rust sometime in the near future. I am curious how long it took you to learn and become proficient?
- iopq 10y agoI've been coding Rust for three years in my free time and I'm still working on it.
- saheel1511 10y agoI'm in no way proficient but I am a TA for an entry level OOP course at an UC. It took me 2 weeks to read through the major topics in Rust. And another month to get a good hold by gradually writing bunch of code.
- echelon 10y agoI am in no way proficient, but I've been using it casually for about a year. I'm just now starting to feel really comfortable with it.
- glennsl 10y agoGood to see bors[0] getting some well deserved credit. That guy's a beast! [0] https://github.com/bors https://github.com/bors
- steveklabnik 10y agoBots are people too!
- Animats 10y agoOK, here's some error handling I wrote about a year ago, for an RSS feed reader. This code calls lots of packages with their own error types. If anything fails, an error bubbles up. Those had to be packed up into a single type for Rust's error handling. What's changed that would make this more concise? pub type FeedResult<T> = Result<T, FeedError>; // return type, result or error // A set of errors that can occur handling RSS or Atom feeds. pub enum FeedError { FeedIoError(io::Error), // error at the I/O level FeedHTTPError(hyper::Error), // error at the HTTP level FeedXMLParseError(xml::BuilderError), // error at the XML level FeedDateParseError(chrono::format::ParseError), // error at the date parsing level FeedUnknownFeedTypeError, // wrong feed type FeedFieldError(String), // required RSS field missing FeedWasHTMLError(String) // expected XML, got HTML } // // Encapsulate errors from each of the lower level error types // impl convert::From<hyper::Error> for FeedError { fn from(err: hyper::Error) -> FeedError { FeedError::FeedHTTPError(err) } } impl convert::From<io::Error> for FeedError { fn from(err: io::Error) -> FeedError { FeedError::FeedIoError(err) } } (More of those are required, one for each enum value...) (Then we need this.) // Convert FeedError to text string. impl fmt::Display for FeedError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &FeedError::FeedIoError(ref xerr) => xerr.fmt(f), // I/O error &FeedError::FeedHTTPError(ref xerr) => xerr.fmt(f), // HTTP error &FeedError::FeedXMLParseError(ref xerr) => xerr.fmt(f), // XML parse error &FeedError::FeedDateParseError(ref xerr) => xerr.fmt(f), // Date parse error &FeedError::FeedUnknownFeedTypeError => write!(f, "Unknown feed type."), &FeedError::FeedFieldError(ref s) => write!(f, "Required field \"{}\" missing from RSS/Atom feed.", s), &FeedError::FeedWasHTMLError(ref s) => write!(f, "Expected an RSS/ATOM feed but received a web page \"{}\".", s) //_(ref xerr) => xerr.fmt(f) // would be convenient, but not allowed in Rust. } } This sort of thing is why I like Python's exception hierarchy. If you catch the higher level errors, you get all the lower level ones, too, without losing the info about what went wrong.
- Arnavion 10y ago
- kccqzy 10y agoExcuse me if this is a stupid question, but when I downloaded the official Mac installer, it's not signed by anyone. I thought in this age we've all recognized that downloaded software should be signed, whether it's using GPG or Apple's signature mechanism? Is there a reason the Rust team decides not to sign their binaries?
- steveklabnik 10y agohttps://github.com/rust-lang/rust/issues/27694 https://github.com/rust-lang/rust/issues/27694 GPG signatures do exist for the tarballs, though, see https://static.rust-lang.org/dist/rustc-1.13.0-src.tar.gz.asc https://static.rust-lang.org/dist/rustc-1.13.0-src.tar.gz.as... for the source, for example, or https://static.rust-lang.org/dist/rustc-1.13.0-x86_64-apple-darwin.tar.gz.asc https://static.rust-lang.org/dist/rustc-1.13.0-x86_64-apple-... for rustc. http://rustup.rs/ http://rustup.rs/ will automatically use all of this if you have it installed and our key imported.
- stirner 10y agoIt seems like a fairly common case for a Rust function to encounter multiple types of error when it runs. My only solution to this is to return a custom error type, but this means manually matching rather than using something like try! or ?. Can someone with more experience than I tell me if there is a simpler approach?
- stjepang 10y agoYes, there is a simpler approach. If your function returns Result<T, Box<Error>>, then you can use try! or ? operator to return any kind of error. It will be automatically boxed and converted into the generic Box<Error>. This works for two reasons: 1) try! and ? don't simply return Err(err) on error case as one might think. They actually return Err(From::from(err)). 2) The standard library has: impl<'a, E: Error + 'a> From<E> for Box<Error + 'a> { ... } Check out this article, starting from "The From trait": http://blog.burntsushi.net/rust-error-handling/ http://blog.burntsushi.net/rust-error-handling/
- stirner 10y agoAnother solution I hadn't considered is to simply impl std::convert::From<SomeError> for your custom error type for each SomeError that might be encountered.
- stirner 10y agoAwesome, thanks. Does returning boxed errors have a performance impact?
- sklopi 10y agoIt should only have an impact when errors actually occur, i think.
- cjg 10y agoWorth noting: "1.13 contains a serious bug in code generation for ARM targets using hardware floats (which is most ARM targets). ARM targets in Rust are presently in our 2nd support tier, so this bug was not determined to block the release. Because 1.13 contains a security update, users that must target ARM are encouraged to use the 1.14 betas, which will soon get a fix for ARM."
- hossbeast 10y agoIs it "written in rust" ?
- steveklabnik 10y agoYes.