These are chat archives for rust-lang/rust

24th
Sep 2018
Urjit Singh Bhatia
@urjitbhatia
Sep 24 2018 00:40
Hmm, I think I found my solution? The statsd Client.time closure should probably be FnOnce. I don’t see any reason why a timer closure should be re-usable.
Berkus Decker
@berkus
Sep 24 2018 07:56
q: how to convert a vector with even number of elements into a map? i'm pretty sure i saw it somewhere but can't find in std or itertools
Michal 'vorner' Vaner
@vorner
Sep 24 2018 08:05
@berkus A vector like key, value, key, value, key, value, …?
Something like vec.into_iter().tupples().collect::<HashMap<_, _>>()
Berkus Decker
@berkus
Sep 24 2018 08:07
yep, vector like this
and tuples() from itertools right?
Michal 'vorner' Vaner
@vorner
Sep 24 2018 08:07
yes
Berkus Decker
@berkus
Sep 24 2018 08:08
thank you!
Berkus Decker
@berkus
Sep 24 2018 08:20
that worked)
trsh
@trsh
Sep 24 2018 10:25
Hi, I have the fallowing code
Box::new(
        db.send(ShopifyOrders(id_nm))
        .map_err(|e| vec![e.to_string()])
        .and_then(move |c| match c {
            Ok(c) => {
                let ret  = json!({"orders": vec![&c.data["order"]]});
                Box::new(empty_shared_fut(ret)
                    .map_err(|e| vec![e.to_string()])
                    .and_then(|r| ok(vec![Some(ret)]))
                )
            }
            Err(_) => {
                Box::new(rest_proxy_manual("orders", q, db)
                    .map_err(|e| vec![e.to_string()])
                    .and_then(|r| ok(vec![Some(r.0)]))
                )
            }
        }),
    )
and errors say's
= note: no two closures, even if identical, have the same type
    = help: consider boxing your closure and/or using it as a trait object
note: match arm with an incompatible type
I don't understand, what else I can Box
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:26
The hint is probably a bit misleading or incomplete. I'll try to explain.
So, you have that closure (or future or whatever) in the Ok branch. That has some hairy type that nevertheless implements trait Future<Item = X, Error = Y>. You have the Err branch with a similar situation. Some hairy (different) type, but implementing the same trait.
trsh
@trsh
Sep 24 2018 10:28
And.. ?
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:28
However, you have nothing from the „outside“ that would force the type of the whole match. The match then takes the type of the first branch and says „Oh, hey, my type is this Box<HairyType1>“. Then the Box<HairyType2> doesn't fit.
So you have to force it to somehow take the type Box<dyn Future<Item = X, Error = Y> and let it cast both boxes to it.
Either by forcing it from the outside (move |c| -> Box<dyn …> { match { … }}`) or by casting the first branch (Box::new(…) as Box<dyn Trait>)
trsh
@trsh
Sep 24 2018 10:29
    = note: expected type `futures::AndThen<futures::MapErr<std::boxed::Box<futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:102:30: 102:53]>, _, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:103:31: 103:54 ret:_]>`
               found type `futures::AndThen<futures::MapErr<std::boxed::Box<futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:109:30: 109:53]>, _, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:110:31: 110:54]>`
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:29
or maybe you could use futures::future::Either. That one allows it without boxing.
trsh
@trsh
Sep 24 2018 10:30
The thing that differs is Closure
@vorner Either makes me sick, never get it working no where
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:34
Strange, it usually works fine for me. Instead of boxing, one branch returns Either::A(the_thing), the other branch returns Either::B(the_other_thing). But you still go the boxing way.
Something like this should work:
Box::new(empty_shared_fut(ret)
                    .map_err(|e| vec![e.to_string()])
                    .and_then(|r| ok(vec![Some(ret)]))
                ) as Box<dyn Future<Item = _, Error = _> + Send
trsh
@trsh
Sep 24 2018 10:37
104 |                   ) as Box<dyn Future<Item = _, Error = _> + Send
    |  _________________________^-
    | |                         |
    | |                         not interpreted as comparison
105 | |             }
    | |_____________- interpreted as generic arguments
or dyn was some type I should have?
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:39
What version of rustc do you have? The dyn prefix is the new way to say that you want a trait object. The old way was without the prefix (just Future<…>), so you might try that.
trsh
@trsh
Sep 24 2018 10:42
Not nightly
rustc --version
rustc 1.26.2 (594fb253c 2018-06-01)
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:43
Right, the newest stable is 1.29. And the dyn could have appeared since then, try without it.
trsh
@trsh
Sep 24 2018 10:43
    |
104 |                   ) as Box<Future<Item = _, Error = _> + Send
    |  _________________________^-
    | |                         |
    | |                         not interpreted as comparison
105 | |             }
    | |_____________- interpreted as generic arguments
but there is a hint
help: try comparing the cast value
    |
101 |                 (Box::new(empty_shared_fut(ret)
102 |                     .map_err(|e| vec![e.to_string()])
103 |                     .and_then(|r| ok(vec![Some(ret)]))
104 |                 ) as Box)<Future<Item = _, Error = _> + Send
Should probably upd rust. Any braking changes?
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:46
Rust (almost) guarantees no breaking changes from stable to stable.
trsh
@trsh
Sep 24 2018 10:47
And the hint doesn't work
error: chained comparison operators require parentheses
   --> manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:104:26
    |
104 |                 ) as Box)<Future<Item = _, Error = _> + Send
    |                          ^^^^^^^^^^^^
    |
    = help: use `::<...>` instead of `<...>` if you meant to specify type arguments
    = help: or use `(...)` if you meant to specify fn arguments
How the f* it should look like :D
Michal 'vorner' Vaner
@vorner
Sep 24 2018 10:49
No, because you want it to not be comparison.
The other part is probably what you want. Box::<Future<Item = _, Error = _>>
In some contexts Rust needs the :: to disambiguise
trsh
@trsh
Sep 24 2018 10:51
Update rust it is
Denis Lisov
@tanriol
Sep 24 2018 10:55
@trsh Looks like you're missing one closing > in your type...
trsh
@trsh
Sep 24 2018 10:57
:D
Anyways, I want to be on latest Stable rust
SO update is going
error: component 'rls-preview' for 'x86_64-unknown-linux-gnu' is unavailable for download beep
trsh
@trsh
Sep 24 2018 11:07
crazy warining comming up
warning: cannot find type `table` in this scope
   --> <table_body macros>:165:33
    |
165 | derive ( Debug , Clone , Copy , QueryId ) ] /// The actual table struct
    |                                 ^^^^^^^ names from parent modules are not accessible without an explicit import
    |
    = note: #[warn(proc_macro_derive_resolution_fallback)] on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
trsh
@trsh
Sep 24 2018 11:15
No braking changes? a?
Wuaaa dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error> cannot be sent between threads safely
Denis Lisov
@tanriol
Sep 24 2018 11:19
You may need to add an explicit + Send
trsh
@trsh
Sep 24 2018 11:23
@tanriol what do u mean by that>?
Denis Lisov
@tanriol
Sep 24 2018 11:39
dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error> + Send
trsh
@trsh
Sep 24 2018 11:44
Same problem
Denis Lisov
@tanriol
Sep 24 2018 11:45
"cannot be sent between threads"?
trsh
@trsh
Sep 24 2018 11:48
dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error> cannot be sent between threads safely
Denis Lisov
@tanriol
Sep 24 2018 11:51
Could you show the code snippet that results in this error?
trsh
@trsh
Sep 24 2018 11:53
    Box::new(
        db.send(ShopifyOrders(id_nm))
        .map_err(|e| vec![e.to_string()])
        .and_then(move |c| match c {
            Ok(c) => {
                let ret  = json!({"orders": vec![&c.data["order"]]});
                //return Box::new(done(Ok(vec![Some(ret)])));
                Box::new(empty_shared_fut(ret)
                    .map_err(|e| vec![e.to_string()])
                    .and_then(|r| ok(vec![Some(ret)]))
                ) as /*Box<dyn Future<Item = _, Error = _> + Send>*/Box<dyn Future<Item = Vec<IOData>, Error = Vec<String>> + Send>
            }
            Err(_) => {
                //Box::new(err(vec!["Shopify order not set".to_string()])),
                Box::new(rest_proxy_manual("orders", q, db)
                    .map_err(|e| vec![e.to_string()])
                    .and_then(|r| ok(vec![Some(r.0)]))
                ) as /*Box<dyn Future<Item = _, Error = _> + Send>*/Box<dyn Future<Item = Vec<IOData>, Error = Vec<String>> + Send>
            }
        })
Future<Item = Vec<IOData>, Error is actually the result from and_then
Denis Lisov
@tanriol
Sep 24 2018 11:56
I'm not seeing any tuples with StatusCode here... looks like this error is for some other future?
Or, possibly, for a later stage of this pipeline.
trsh
@trsh
Sep 24 2018 11:57
And all because of freaking mismatch of clause
@tanriol
error[E0277]: `dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>` cannot be sent between threads safely
   --> manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:108:17
    |
108 | /                 Box::new(rest_proxy_manual("orders", q, db)
109 | |                     .map_err(|e| vec![e.to_string()])
110 | |                     .and_then(|r| ok(vec![Some(r.0)]))
111 | |                 ) as /*Box<dyn Future<Item = _, Error = _> + Send>*/Box<dyn Future<Item = Vec<IOData>, Error = Vec<String>> + Send>
    | |_________________^ `dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>`
    = note: required because it appears within the type `std::boxed::Box<dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>`
    = note: required because it appears within the type `futures::MapErr<std::boxed::Box<dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:109:30: 109:53]>`
    = note: required because it appears within the type `futures::future::chain::Chain<futures::MapErr<std::boxed::Box<dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:109:30: 109:53]>, futures::FutureResult<std::vec::Vec<std::option::Option<serde_json::Value>>, std::vec::Vec<std::string::String>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:110:31: 110:54]>`
    = note: required because it appears within the type `futures::AndThen<futures::MapErr<std::boxed::Box<dyn futures::Future<Item=(serde_json::Value, http::StatusCode), Error=actix_web::Error>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:109:30: 109:53]>, futures::FutureResult<std::vec::Vec<std::option::Option<serde_json::Value>>, std::vec::Vec<std::string::String>>, [closure@manu/src/applications/api/gqls/doc_templates/workers/shopify_order.rs:110:31: 110:54]>`
    = note: required for the cast to the object type `dyn futures::Future<Item=std::vec::Vec<std::option::Option<serde_json::Value>>, Error=std::vec::Vec<std::string::String>> + std::marker::Send`
Full err
Denis Lisov
@tanriol
Sep 24 2018 12:03
Ooh, wonderful. What's the signature of rest_proxy_manual?
Looks like a + Send may be needed in its return value.
trsh
@trsh
Sep 24 2018 12:09
new problems
db: &Addr<DbExecutor>,
    |       -- consider changing the type of `db` to `&'static actix::Addr<applications::db::DbExecutor>`
...
94  | /     Box::new(
95  | |         db.send(ShopifyOrders(id_nm))
96  | |         .map_err(|e| vec![e.to_string()])
97  | |         .and_then(move |c| match c {
...   |
113 | |         })
114 | |     )
    | |_____^ lifetime `'static` required
I think I need some rf
Denis Lisov
@tanriol
Sep 24 2018 12:10
You can clone actix::Addr
trsh
@trsh
Sep 24 2018 12:15
that doesn't seem to help
As it must live in some closure in future
but i will experiment
trsh
@trsh
Sep 24 2018 12:22
Got it compiling
@tanriol are u familiar with newest stable rust names from parent modules are not accessible without an explicit import warning.
Since upgrade I have all over the place
trsh
@trsh
Sep 24 2018 12:27
Here is my code > https://pastebin.com/yhMw9uRp
and here is the warning. At moment it makes less sense for me
warning: cannot find type `NewUser` in this scope
  --> manu/src/applications/api/models/users.rs:23:10
   |
23 | #[derive(Insertable)]
   |          ^^^^^^^^^^ names from parent modules are not accessible without an explicit import
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
Kelly Thomas Kline
@kellytk
Sep 24 2018 12:28
I'm attempting to use a private crate named core in a binary crate and it's generating an error I don't quite understand. It appears that core is reserved which is probably the cause. Where can I find a list of all reserved names?
Kelly Thomas Kline
@kellytk
Sep 24 2018 12:29
@trsh core isn't in that list though
Denis Lisov
@tanriol
Sep 24 2018 12:30
@trsh Is your diesel version up-to-date?
trsh
@trsh
Sep 24 2018 12:33
Not really
trsh
@trsh
Sep 24 2018 12:38
Lets try to upd
@tanriol same
trsh
@trsh
Sep 24 2018 12:43
From Github thread seems like supresing for now
David Vo
@auscompgeek
Sep 24 2018 14:24
@kellytk core is the name of a builtin crate (it's std but without the memory allocation/OS-specific stuff), so you'll have to pick a different name for your crate.
the list of builtin crates is very small, but I can't remember where I actually read it.
iirc it's just core, std, proc_macro
nothing should stop you from naming anything else core though.
Iurii Malchenko
@yurique
Sep 24 2018 15:23

hi everyone!
I have a question: is it possible in rust to have a static dispatch for enum variants? like in (pseudo):

trait MyTrait {
  fn test(&self) -> f64;
}
enum MyEnum {
  A(f64),
  B(f64)
}

Impl MyTrait for MyEnum.A {
  fn test(&self) -> f64 { self.0 } ;
}
Impl MyTrait for MyEnum.B {
  fn test(&self) -> f64 { -self.0 } ;
}

(background: I added the optimizations I made for the rust implementation into the original Scala code, and I’m seeing in the benchmarks that Scala version outperforms Rust by ~90% (on the exact same test data) - with the code that is not creating/cloning any objects, just traverses the tree and does some computations; which doesn’t make sense unless the functions that do a lot of pattern matching on the enums (and unboxing) are slow due to no static dispatch; or I’m missing something else :) )

right now I have it like this:
enum MyEnum {
  A(f64),
  B(f64)
}

impl MyEnum {
  fn test(&self) -> f64 { match self {
    MyEnum.A(v) => v,
    MyEnum.B(v) => -v,
  } } ;
}
red75prime
@red75prime
Sep 24 2018 15:28
Do you build release version? cargo build --release
Iurii Malchenko
@yurique
Sep 24 2018 15:28
yes
and I use cargo bench, which I believe does release, too
I mean it’s still fast, but I’m surprised jvm is that much faster
like 12ms vs 19ms
(well, not really 90%, though :) )
red75prime
@red75prime
Sep 24 2018 15:31
Enum matching doesn't do dynamic dispatch. That's for sure.
Iurii Malchenko
@yurique
Sep 24 2018 15:31
yeah, but I mean it still has to match and deconstruct, right?
[ I actually have no idea what’s the reason; just guessing :) ]
red75prime
@red75prime
Sep 24 2018 15:37
Speed differences are probably due to dynamic allocation. Garbage collected memory allows faster deallocation, if I'm not mistaken.
Iurii Malchenko
@yurique
Sep 24 2018 15:38
yeah, but in this particular benchmark - nothing is getting allocated in the hot path - only f64/Double values are calculated and returned (as far as I can tell)
is it expensive to to v.iter() (where v is a Vec)?
red75prime
@red75prime
Sep 24 2018 15:42
No, it should optimize well.
Iurii Malchenko
@yurique
Sep 24 2018 15:45
yay! I found it. There was a logical bug (kind of - the value was already available in one case, but it was recalculated; nothing crazy - a fn call with a (small-ish) array traversal with comparing (though things compared were the strings); but with this fixed it’s now >twice faster than scala)
:)
red75prime
@red75prime
Sep 24 2018 16:00
👍
Ichoran
@Ichoran
Sep 24 2018 16:32
@yurique - In my experience, that is what you can typically expect. About 2x faster Rust than Scala. Details matter, particular cases vary wildly. But it happens often enough.
Iurii Malchenko
@yurique
Sep 24 2018 19:46

I have another question :)

is it possible to have a trait, like trait MyTrait, implemented for a bunch of structs, and have a function that returns something that implements that trait?

I’m thinking something like this:

fn make_it() -> &T where T: MyTrait { … }

Is it possible then to have a function that returns, say, a map from String to somethings that implement the trait (not the same struct). Like (pseudo):

fn make_them() -> HashMap<String, & T> where T: MyTrait { 
   let m = HashMap::new();
   m.insert(“a”, StructA::new());
   m.insert(“b”, StructB::new());
   m
}
(I want to see if I can implement the whole thing without enums, with static dispatch and see if it makes a difference)
or, in general, is there a way to represent in types “something (unknown) that implements a given trait”? maybe with Boxes/Rcs/etc?
[ I know I should read that book again to remind myself about all of it :) ]
James McCoy
@jamessan
Sep 24 2018 19:54
@yurique Sounds like you're looking for impl Trait
Iurii Malchenko
@yurique
Sep 24 2018 19:55
I actually tried it, but got a bunch of cannot be made into an object :) (but I’m most likely doing it wrong)
Thiez
@Thiez
Sep 24 2018 20:03
You cannot use impl Trait for different types that implement the same trait
Iurii Malchenko
@yurique
Sep 24 2018 20:15

I see.
And what about fn make() -> Rc<<MyTrait>? It seems to work with a simple case at play.rust-lang.org

But I’m getting the trait cannot be made into an object

Thiez
@Thiez
Sep 24 2018 20:15
Can you show me your trait?
Kelly Thomas Kline
@kellytk
Sep 24 2018 21:36
If a binary uses two libraries A and B, and A uses B directly, how can the binary disambiguate them so cargo build doesn't fail with a lockfile error?
Kelly Thomas Kline
@kellytk
Sep 24 2018 21:59
https://github.com/rust-lang/cargo/issues/5267#issuecomment-392571606 "at the fundamental layer having two crates in the same namespace from the same source (aka path dependencies) which are named the same is an error" why is that? I'm not certain my use falls into the category of same namespace, that said
Iurii Malchenko
@yurique
Sep 24 2018 23:28

Another quick update from me: I wanted to test it out with static dispatch (it was itching me that rust can do better and I’m just not doing it completely right :)

so I rewrote the whole thing without enums: made traits, and each enum variant became a struct with an impl for that trait; also I changed Box<> for nested fields to Rc<>

and the results:

  • the old version was doing ~200 “units of work” in ~500ms
  • new version does 550 “units of work” in 70ms

p.s. 😲

Ichoran
@Ichoran
Sep 24 2018 23:33
:+1:
Iurii Malchenko
@yurique
Sep 24 2018 23:34
actually, in the benchmarks locally I didn’t see that much improvement in the part I tried to optimize (where most of the static dispatch would replace pattern matching; just about 10% improvement there), but rather the construction of those tree-objects went down from 1,030,436 ns/iter to mere 47,806 ns/iter (not sure why; Box vs Rc, I guess; clone() benchmarks show a ridiculous improvement, like: 34,261 ns/iter -> 2 ns/iter - the Rc clone on the top level is just memcpy+counter increment, and it is a deep tree, so I can understand the improvement vs Box)
Ichoran
@Ichoran
Sep 24 2018 23:34
Yeah, Box allocates on the heap. If you don't actually need something on the heap it's way faster to not use Box.
But you probably should be borrowing the box, not cloning it, if you can get away with Rc.
Iurii Malchenko
@yurique
Sep 24 2018 23:36
Yeah
On the one hand, I wish I went with Rc from start (I actually did, but soon got confused by some error messages and moved to boxes, afair)
But on the other hand - this is exciting to get all of these results in a sequence :)
Ichoran
@Ichoran
Sep 24 2018 23:37
Hopefully whatever you're doing in the end can use Rc or can box at the end after everything's built. It's not hard to pull out a benchmark that isn't representative of the usage patterns you'll need in production.
Iurii Malchenko
@yurique
Sep 24 2018 23:37

But you probably should be borrowing the box, not cloning it, if you can get away with Rc.

the data tree (trees) actually shares a lot of parts, with a lot of manipulation, so I couldn’t get away with just borrowing

Hopefully whatever you're doing in the end can use Rc or can box at the end after everything's built. It's not hard to pull out a benchmark that isn't representative of the usage patterns you'll need in production.

Oh, I already got rid of all Boxes :)

It's not hard to pull out a benchmark that isn't representative of the usage patterns you'll need in production.

For the bench I used a real-world task, one of the hardest it will ever see; and used the same data-set we have on prod

(it’s a kind of complicated search over the pre-existing data to find a best fit for the requirements in a task)
And I’m actually testing it with the real FE (not prod, though :) ) and seeing huge improvements in latency.
So I’m really happy with these results :)

Ichoran
@Ichoran
Sep 24 2018 23:41
Excellent!
Iurii Malchenko
@yurique
Sep 24 2018 23:42
Yeah
thanks a lot to everyone who helped! your help is priceless! :)