These are chat archives for rust-lang/rust

14th
Dec 2017
Alkis Evlogimenos
@alkis
Dec 14 2017 10:47
Is it not possible to match an Option<T> inside an struct like enum variant?
Jonas Platte
@jplatte
Dec 14 2017 10:48
@alkis I don't understand exactly what you're asking but the answer is most likely that it is possible
I'm guessing you have some code already, but you get an error that you don't understand?
Alkis Evlogimenos
@alkis
Dec 14 2017 10:50
enum V {
  A {
    foo: Option<u64>,
    bar: u64,
  },
};

match v {
  V::A {
    Some(foo),  // compiler error here "expected `,`, found `(`"
    bar,
  } => { /* do something */ },
  _ => {},
}
Aleksey Kladov
@matklad
Dec 14 2017 10:51
@alkis you'll need V::A { foo: Some(foo), bar }
Alkis Evlogimenos
@alkis
Dec 14 2017 10:51
@matklad yey that works!
Thank you :-)
When I use workspaces the crates the workspaces depend on do not get pulled in the docs. Passing --all does not change this. The same happens with tests. Running cargo test --all at the top level does not run the tests of inner crates. I am guessing they are related. Any hint on what I might be doing wrong?
Aleksey Kladov
@matklad
Dec 14 2017 10:57
@alkis yep, cargo test --all is supposed to test all workspace members, so my guess would be that those crates are not actually workspace members?
Alkis Evlogimenos
@alkis
Dec 14 2017 10:58
To make them workspace members do I need both mylib = { path = "mylib" } and an entry in workspaces or is the entry in workspaces superfluous?
or maybe I need an empty [workspace] section in top level Cargo.toml?
Aleksey Kladov
@matklad
Dec 14 2017 10:59
You def need [workspace] section
Alkis Evlogimenos
@alkis
Dec 14 2017 11:01
Ok now it works :-)
David
@yenicelik
Dec 14 2017 11:13
Hey guys
So I'm currently trying to do some error handling without nesting many match statement, using the and_then constructs... However, I am getting type errors I do not understand..

I have the following code:

    create_post(request_body, uri)
        .and_then(|value: Value| {
            value.get("data")
        })
        .and_then(|data| {
            serde_json::from_value(data.clone())
        })
        .and_then(|mut resp: types::ResponseOrder| {
            types::convert(resp.0)
        });

where create_post has the return type Option<serde_json::Value>

And I am getting the error message:
error[E0308]: mismatched types
   --> src/coinigy_live.rs:175:13
    |
175 |             serde_json::from_value(data.clone())
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `types::_IMPL_DESERIALIZE_FOR_SingleMarketTemp::_serde::export::Option`, found enum `types::_IMPL_DESERIALIZE_FOR_SingleMarketTemp::_serde::export::Result`
    |
    = note: expected type `types::_IMPL_DESERIALIZE_FOR_SingleMarketTemp::_serde::export::Option<_>`
               found type `types::_IMPL_DESERIALIZE_FOR_SingleMarketTemp::_serde::export::Result<_, serde_json::Error>`

error[E0308]: mismatched types
   --> src/coinigy_live.rs:178:13
    |
178 |             types::convert(resp.0)
    |             ^^^^^^^^^^^^^^^^^^^^^^ expected enum `types::_IMPL_DESERIALIZE_FOR_SingleMarketTemp::_serde::export::Option`, found struct `std::vec::Vec`
    |
    = note: expected type `types::_IMPL_DESERIALIZE_FOR_SingleMarketTemp::_serde::export::Option<_>`
               found type `std::vec::Vec<_>`
I assume the problem is that I am changing between type result and option, but i have no idea how to fix it :D
Aleksey Kladov
@matklad
Dec 14 2017 11:16
You are correct that the problem is in mixing options and results
David
@yenicelik
Dec 14 2017 11:17
but both option and result implement an and_then, right?
Aleksey Kladov
@matklad
Dec 14 2017 11:17
The simplest fix would be to add .ok calls on result-returing mehtods
David
@yenicelik
Dec 14 2017 11:18
but how do I handle the errors then? I mean I don't want it to panic
Aleksey Kladov
@matklad
Dec 14 2017 11:18
.ok casts result into an option, turning Err(e) into None.
David
@yenicelik
Dec 14 2017 11:18
oh
Aleksey Kladov
@matklad
Dec 14 2017 11:19
And how do you handle errors now? Presumable, the outer function returns some kind of Result. In that case, using ? operator might actually be easier then and_then chaining.
David
@yenicelik
Dec 14 2017 11:20
I didn't implement error handling yet, I was just trying to create a function that just does not panic :D
But doesn't ? return different types of errors?
Aleksey Kladov
@matklad
Dec 14 2017 11:20
Yeah, different types of errors is a fundamental problem
David
@yenicelik
Dec 14 2017 11:20
i.e.
func1()?;
func2()?;
does not allow the function to have a single error-return types?
shieeeeet
so what is the best solution for error-handling without nesting thousands of match-statements? do you think the above solution is ok?
Aleksey Kladov
@matklad
Dec 14 2017 11:21
Not exactly. The trick is that ? automatically uses From conversion, so if your function returns an error which can be constructed from any of inner errors, you're good.
@yenicelik have you looked into the new failure crate?
David
@yenicelik
Dec 14 2017 11:22
nope, i'm really new into rust :/
the doc is a little 'sparse'.. is it this one? https://docs.rs/failure/0.1.1/failure/
Aleksey Kladov
@matklad
Dec 14 2017 11:24
That's fine! have you read https://doc.rust-lang.org/book/first-edition/error-handling.html ? :) It'll give you are thorough understanding of the basic mechanisms.
David
@yenicelik
Dec 14 2017 11:24
yep, did that :)
so should i best just implement From traits for the different error types?
Aleksey Kladov
@matklad
Dec 14 2017 11:25
Yep, that one! Here are some more docs: https://boats.gitlab.io/failure/
David
@yenicelik
Dec 14 2017 11:25
uhh, i love some sample code
Aleksey Kladov
@matklad
Dec 14 2017 11:26
Yeah, the general idea is that for applications you have a single error type which unifies all errors from all the libraries you use, and then ? and from magic allows you to write pretty straight-line code.
David
@yenicelik
Dec 14 2017 11:26
that's sexy
imma try to do that then :) thx a lot, i'll get back when i'm desperately stuck again :D
Aleksey Kladov
@matklad
Dec 14 2017 11:26
The problem is, defining all From impls yourself is way to boring, so that's where failure comes in
David
@yenicelik
Dec 14 2017 11:26
uhhh
tell me more :D
Aleksey Kladov
@matklad
Dec 14 2017 11:28
@yenicelik I suggest starting with this pattern: https://boats.gitlab.io/failure/use-error.html
David
@yenicelik
Dec 14 2017 11:29
cool
thanks a lot! :)
Sergey Elantsev
@serejkus
Dec 14 2017 11:39
had anyone measured performance cost of moving from enum of errors to failure::Error?
failure::Error has a Box inside with backtrace, so how does it compare in performance to enum of errors?
Aleksey Kladov
@matklad
Dec 14 2017 11:42

@serejkus that would be highly application specific, so I doubt a useful one-fits-all benchmark is possible.

That said, I expect for the typical "errors are a rare failure cases", the failure::Error might acutely be faster, because it's size_of is small.

If you hit error path frequently and worry about allocation, that probably means that you return type is highly specific and should probably not implement neither Fail nor std::Error
Sergey Elantsev
@serejkus
Dec 14 2017 11:45
I guess that network applications have some non-zero error rate quiet often. And making errors not that cheap may reduce the capacity of such an applications significantly
Michal 'vorner' Vaner
@vorner
Dec 14 2017 11:45
I agree with the first (the return type being specific and having own implementation), but having results where the second thing doesn't implement either is often painful on the caller side.
Network applications have non-zero error rate, but the ratio of normal calls vs. errors is usually (at least whenever the thing works as it should) well in favor of the normal scenario.
So you want to make the normal/happy case faster, even at a slight slowdown of the error case.
Aleksey Kladov
@matklad
Dec 14 2017 11:47
@vorner my thinking also was if this "error" happens frequently, then you'll probably be doing some explicit matching on it and some specific error handing, so implementing generic Error traits is not strictly necessary.
David
@yenicelik
Dec 14 2017 11:49
@matklad thanks again for the help, it works like a charn and looks good :)
Michal 'vorner' Vaner
@vorner
Dec 14 2017 11:50
@matklad Not strictly necessary, but still, if part of public API (as opposed as being internal somewhere inside a crate or company or whatever) I'd opt for erring on the side of implementing more traits than less, if possible.
Alkis Evlogimenos
@alkis
Dec 14 2017 11:50
@vorner you also want to be robust under stress. Increasing the amount of work done while handling exceptional load is the anti-pattern for robust services. Surely failure::Error can't have the non-error case be as fast as the error case but ignoring how slow the error case is because it doesn't happen often is not a good strategy.
Michal 'vorner' Vaner
@vorner
Dec 14 2017 11:52
@alkis I guess you're afraid of the overhead too much. It won't be much slower. Heap allocation isn't poison. It's probably still way faster than doing the syscall to kernel to get the data or error back in the first place.
And besides, a TCP connection can transfer gigabytes of data over its lifetime, but error only once.
Alkis Evlogimenos
@alkis
Dec 14 2017 11:54
@vorner agreed if the errors are 1:1 with network accesses. If errors are coming from parsing the data and they happen in a loop excessive allocations might be a problem.
Alkis Evlogimenos
@alkis
Dec 14 2017 12:01
@vorner but I am guessing this is what the discussion above was concluding: don't return too many errors or if you do, do not make them into the failure::Error :-)
Aleksey Kladov
@matklad
Dec 14 2017 12:02
@alkis yep, this can be rephrased as "use Error in applications and custom error type in libraries".
sort-of rephrased :)n
Sergey Elantsev
@serejkus
Dec 14 2017 12:04
but Failure is more convinient than Error with error_chain/quick_error, so it's easier to start with
Aleksey Kladov
@matklad
Dec 14 2017 12:05
failure crate does make creating custom error types rather easy via custom derive.
Sergey Elantsev
@serejkus
Dec 14 2017 12:05
so, this may lead to a problem if you (or the authors of the crate you're dependent on) haven't thought upfront
can't we take the best of both worlds?
Michal 'vorner' Vaner
@vorner
Dec 14 2017 12:06
The Fail trait in itself does not require you to use failure::Error.
You can just return something that implements Fail without any heap allocation.
And leave it up to the application to decide if it wants to custom-handle it (because of performance) or wrap it in failure::Error (and pay the price)
Sergey Elantsev
@serejkus
Dec 14 2017 12:08
that's the good point
Alkis Evlogimenos
@alkis
Dec 14 2017 12:09
So perhaps this is what libraries should do? Return something that implements the Fail trait and avoid allocations, and applications choose the point where they convert those to Errors?
Sergey Elantsev
@serejkus
Dec 14 2017 12:10
but doesn't it return us to a problem with a sort of too explicit derives? We can return std::Error either
it would be great to have a way to have zero-cost error types (like enum of Errors) without being too explicit about implementing std::Error trait requirements
Aleksey Kladov
@matklad
Dec 14 2017 12:12
And this is exactly what failure's custom derive (+ Fail trait, which is better then std::Error) gives you?
Sergey Elantsev
@serejkus
Dec 14 2017 12:12
like, failure crate saves a lot of time with its awesome macros and it's really easy to use it
Aleksey Kladov
@matklad
Dec 14 2017 12:12
Sergey Elantsev
@serejkus
Dec 14 2017 12:14
hm, so you can take the best of both worlds: have a custom error type with zero runtime overhead (compared to enum of errors) and use convinient macros
and the return type is Result<T, YourDerivedError>?
Aleksey Kladov
@matklad
Dec 14 2017 12:15
Yup!
Sergey Elantsev
@serejkus
Dec 14 2017 12:15
wow, cool, hadn't thought about this
Aleksey Kladov
@matklad
Dec 14 2017 12:17

have a custom error type with zero runtime overhead (compared to enum of errors)

Be careful here though, a common performance pitfall with enums for errors is that size_of of the enums can get quite large, which inflates the size of Result<T, MyError>, which pessimises the happy path. Sometimes it's better to just box the stuff instead of copying kilobytes of stack data over and over :)

That is, enum of errors is not zero-cost either, you'll need to pay attention to size_of.
Alkis Evlogimenos
@alkis
Dec 14 2017 12:18
when using workspaces: can I have dependencies between the child crates? for example main crate is M, and has child crates A, B, C. Can B depend on A?
Aleksey Kladov
@matklad
Dec 14 2017 12:18
Yep, just a usual path dependency would do foo = {path = "../foo" }
Alkis Evlogimenos
@alkis
Dec 14 2017 12:18
great!
Sergey Elantsev
@serejkus
Dec 14 2017 12:21
@matklad thanks, that's the good point, too. Most of the time errors are reasonably small, but if it happens that you need to store something that can be used for error handling, it may be better to box that big parts of data.
Bernhard Schuster
@drahnr
Dec 14 2017 12:58
Hi
I am trying to have a client with a state that handles a specific message format using futures and tokio
So now I end up with a client struct on which I call send which returns a future
But that prevents usage of client().connect().and_then(move |x| client.send(packet).and_then(move |x| { Ok(client.send(packet)) }).flatten() where send and connect borrow mutably...
How can this be solved?
Alkis Evlogimenos
@alkis
Dec 14 2017 16:06
@drahnr can you give more context? Perhaps an example?
Bernhard Schuster
@drahnr
Dec 14 2017 16:07
I trying to shape the API for a MqttClient library
Alkis Evlogimenos
@alkis
Dec 14 2017 16:09
so you want to wrap a TcpStream and expose a pub/sub api on top of it?
I would look how websocket libraries do something similar. I think tungstenite is a good example
Bernhard Schuster
@drahnr
Dec 14 2017 16:27
yes
thank you, I'll check it out
Sander Maijers
@sanmai-NL
Dec 14 2017 16:34
Who has an example of how to return an iterator using impl Trait from a function that calls another one, with the same impl Trait return type? Right now I get this compilation error:
    = note: expected type `std::result::Result<std::boxed::Box<impl std::iter::Iterator>, _>` (anonymized type)
               found type `std::result::Result<std::boxed::Box<impl std::iter::Iterator>, _>` (anonymized type)
I'm supposed to box somewhere but it doesn't seem to help in this case
Denis Lisov
@tanriol
Dec 14 2017 20:12
I'm not sure whether that's possible at all with impl Trait.
Zakarum
@omni-viral
Dec 14 2017 20:18
@sanmai-NL Aren't you trying to return two different anonymous types?
Like this
fn foo(pick: bool) -> impl Iterator<Item=usize> {
  if pick {
    (0..10).map(|_| 42)
  } else {
    (0..10).map(|_| 42)
  }
}
Jonas Platte
@jplatte
Dec 14 2017 20:23
Box<impl Trait>? I don't see why you would ever need that
I guess theoretically it could be useful, but are you sure you want to box the anonymous type?
Sander Maijers
@sanmai-NL
Dec 14 2017 21:38
@jplatte, nope I do not want to box it, but this was suggested in a comment to a GH issue for this
Jonas Platte
@jplatte
Dec 14 2017 21:38
@sanmai-NL Usually that is an alternative to using impl Trait. You don't use both.
Sander Maijers
@sanmai-NL
Dec 14 2017 21:39
@omni-viral : yes, that what's it amounts to. The two anonymous types are essentially different, I want to use the same type.
Jonas Platte
@jplatte
Dec 14 2017 21:39
@sanmai-NL Then you use Box<Trait>
impl Trait means that it is one concrete type that you can't name and/or don't want to expose as part of your API
Box<Trait> actually does runtime dispatch so it is possible to return different implementors of the same trait in a function that returns that.
Sander Maijers
@sanmai-NL
Dec 14 2017 21:42
@jplatte, I'm trying to find the relevant GH issue where this was suggested. Thanks for clarifying
Cameron Mochrie
@cjmochrie
Dec 14 2017 23:51
:wave: :wave: :wave:. I'm working through advent of code again this year. I keep bumping up against the borrow checker in regards to HashMap. The problem is typically that I set up a HashMap with my data structures. I retrieve some value, and based on that value I need to mutate some different value. This doesn't work because I've borrowed the first value from the HashMap, and can't borrow it again mutably to mutate a different value. Here's a playpen link with a minimal implementation https://play.rust-lang.org/?gist=d35c96f580149e29de1dc2cb1c39ecbf&version=stable.
Is there a) some way to use a HashMap that can accomplish this, or b) something totally different/more idiomatic I should be doing to accomplish this behavior?