These are chat archives for rust-lang/rust

2nd
Apr 2019
Tom Cumming
@tomcumming
Apr 02 09:27
can I set enum tag size?
i have two options, i wanna store it in less bytes
its taking 8 bytes for a bool
oh even std::mem::size_of::<(u8, u64)>() is 16 bytes
Zakarum
@omni-viral
Apr 02 09:38
@tomcumming It is because of alignment
u64 must be aligned to 8 bytes and takes 8 bytes
So there are 7 bytes padding in (u8, u64)
Somewhere
Tom Cumming
@tomcumming
Apr 02 09:39
i guess i have to use a struct then
with repr(whatever)
Zakarum
@omni-viral
Apr 02 09:40
repr(packed)?
It can slow down memory access to u64
Georg Semmler
@weiznich
Apr 02 10:16
Is there any easy way to find out why the item-bodies checking pass is taking a lot of time (~1200s) whereas codegen is quite fast (~100s)?
Tom Cumming
@tomcumming
Apr 02 10:35
@omni-viral this is for writing to disk
maybe i should just write a Read instance?
Tim Robinson
@1tgr
Apr 02 10:37
Don’t look directly at the binary representation of Rust types, it’s not defined
Zakarum
@omni-viral
Apr 02 10:38
@1tgr Why?
Tim Robinson
@1tgr
Apr 02 10:38
In particular, the compiler can do clever things with your enum or your (u8, u64) when it’s part of a larger data structure
Zakarum
@omni-viral
Apr 02 10:39
@1tgr some primitives and repr(not-rust) types has defined layout
Tim Robinson
@1tgr
Apr 02 10:39
Sure, but I think that rules out the tuple
The enum can be made to look like a C enum
But you’re better off using something like the byteorder crate to write your own serialisation code where the format is explicit, or use a standard binary format with serde
David O'Connor
@David-OConnor
Apr 02 13:14
Hey dudes: Question. I'm attempting to create an API where the user passes function which returns either a Vec<T>, or T. (T is a placeholder for a type I use) How would you approach this, and what would the signature of this fn look like internally? The most straightfwd approach I tried was this:
impl From<T> for Vec<T> {
    fn from(el: T) -> Self {
        vec![T]
    }
}

type ViewFn =  fn() -> Into<Vec<T>>;
Zakarum
@omni-viral
Apr 02 13:14
Either<Vec<T>, T>?
David O'Connor
@David-OConnor
Apr 02 13:15
Sry, accidentally hit enter while in prog of fleshing this out
Zakarum
@omni-viral
Apr 02 13:15
You can't implement From for Vec
David O'Connor
@David-OConnor
Apr 02 13:15
Haven't heard of either though...!
Zakarum
@omni-viral
Apr 02 13:15
IDK why it is not in std
But either crate provides one

It is basically

enum Either<L, R> {
  Left(L),
  RIght(R),
}

with bunch of functions

David O'Connor
@David-OConnor
Apr 02 13:17
Neat. This sounds like the soln. So the user can pass the normal fn without using either, and the fn I accept internally is Either?
Zakarum
@omni-viral
Apr 02 13:18
No
David O'Connor
@David-OConnor
Apr 02 13:18
(Note the other approaches I've been at tempting are to have a ReturnType structs or traits that thinly wrap, but no luck there eitehr)
Zakarum
@omni-viral
Apr 02 13:19
If you want user to pass fn()->T or fn()->Vec<T> you need to take Either<fn()->T, fn()->Vec<T>>
David O'Connor
@David-OConnor
Apr 02 13:19
That does sound exactly like what I'm looking for
Ichoran
@Ichoran
Apr 02 14:55
@omni-viral - Either is isomorphic to Result, so having both in the standard library is a little redundant. (Yes, it's handy to have both the biased and unbiased sum types available, but really, you can do it with Result.)
Zakarum
@omni-viral
Apr 02 14:57
@Ichoran Either is isomorphic to any enum with two variants that hold value of generic type
Michal 'vorner' Vaner
@vorner
Apr 02 14:57
Ichoran: You probably shouldn't. First, the Result<T, Vec<T>> would look like something is wrong with Vec<T>.
Zakarum
@omni-viral
Apr 02 14:57
But think about user who would call foo.bar(x, y, Err(|x| x * 42))
Ichoran
@Ichoran
Apr 02 14:57
Yeah, the ergonomics are not the best.
Michal 'vorner' Vaner
@vorner
Apr 02 14:58
Second, Either has whole bunch of trait implementations, like Read where L: Read, R: Read
Zakarum
@omni-viral
Apr 02 14:59
It would also make sense for Either to be in std so that crates that define traits can implement it for Either
Ichoran
@Ichoran
Apr 02 14:59
But even so, I can see some reason to only include one generic two-item sum type in the standard library.
Library is smaller, and you don't have to worry about whether you use Result, Either, or a custom sum type. And you don't have to worry about all the Result-Either conversions.
Zakarum
@omni-viral
Apr 02 15:00
And I can see some reason for Either to be there instead of Result ;)
Ichoran
@Ichoran
Apr 02 15:01
Yes, well, Scala has Either and not Result, with Right being the desired result and Left being the error case, by default. It works okay. Having a dedicated error type is better, though; lots of Scala libraries define something that is basically Rust Result.
Zakarum
@omni-viral
Apr 02 15:01
Same in Haskell
Ichoran
@Ichoran
Apr 02 15:02
And there is the same awkwardness with multiple representations and conversions and so on. So I don't know if there exists a clearly superior way to do it. Seems like there are inherent tradeoffs between a simple crisp interface and the expressivity to make your meaning clear in a wide variety of situations.
@David-OConnor - Anyway, either crate is cool.
Zakarum
@omni-viral
Apr 02 15:03
Traits from multiple crates implemented for Either is objectively good thing
Which isn't the case, because who would add new dependency just to implement his traits for Either?
Ichoran
@Ichoran
Apr 02 15:04
Yeah, that's a good point. Okay, you're probably right: would be better if Either was in std.
Riley Cat
@WreckedAvent
Apr 02 16:41
I don't really see a point in having both Either and Result since they are effectively the same type, just one has variants that you have to memorize as to what it means and the other has obvious variants
anyway @David-OConnor I'm not sure what your use case is exactly for returning either a single element or a vec of them, but you can just wrap the single element in a vec and check if there's just one element or create an enum that better describes your domain
I would not suggest using an Either here since by convention one "side" is used for errors
ambiso
@ambiso
Apr 02 17:16

Hello!

I have a tiny question about the tokio library.

I'm trying to find a more idiomatic way to do the following:

                let msg: Result<WsMsg, WebSocketError> = serde_json::from_str(&msg)
                    .map_err(|e| ResponseError("The server has replied with an unknown message"));
                if msg.is_err() {
                    return err(msg.unwrap_err());
                }
                let msg = msg.unwrap();

I've tried using the ? operator on the FuturesResult returned by err, but for some reason FuturesResult doesn't implement the Try trait.

Zakarum
@omni-viral
Apr 02 18:04

@WreckedAvent

one has variants that you have to memorize as to what it means and the other has obvious variants

Exactly, and sometimes you need other variants

i.e. sometimes it is not success and error
Victor Lopes
@vlopes11
Apr 02 18:21

Hello Rustaceans! To implement Clone for a Box of a trait instance with a specific lifetime, what's the best practice? Example:

trait SomeTrait: Clone + Sized {
    fn some_method(&self) -> &bool;
}

#[derive(Clone)]
struct SomeStruct {
    pub val: bool,
}
impl SomeTrait for SomeStruct {
    fn some_method(&self) -> &bool {
        &self.val
    }
}

struct OtherStruct<'a> {
    pub some_box: Box<'a + SomeTrait>,
}

fn main() {}

This code will produce this:

error[E0038]: the trait `SomeTrait` cannot be made into an object
  --> src/main.rs:16:5
   |
16 |     pub some_box: Box<'a + SomeTrait>,
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait` cannot be made into an object
   |
   = note: the trait cannot require that `Self : Sized`
Ingvar Stepanyan
@RReverser
Apr 02 18:24
the error message says that your trait cannot be used with dynamic dispatch, it's not strictly related to cloning
Riley Cat
@WreckedAvent
Apr 02 18:24
@ambiso the more idiomatic approach would be to use a combinator like and_then
Ingvar Stepanyan
@RReverser
Apr 02 18:24
what exactly are you trying to do? do you actually want dynamic dispatch inside of OtherStruct or can you make it generic?
Victor Lopes
@vlopes11
Apr 02 18:24
I need a dynamic dispatch without 'static lifetime
Maybe an usage example is a Vec with different implementations of SomeTrait?
Ingvar Stepanyan
@RReverser
Apr 02 18:26
I see. And by cloning you mean you want to actually be able to clone data behind the trait?
If you remove : Clone + Sized bound, your code will compile as expected, but I'm not sure if you need it too...
Victor Lopes
@vlopes11
Apr 02 18:28
Understood. And impl Clone for Box<SomeTrait>?
Ingvar Stepanyan
@RReverser
Apr 02 18:29
no, I don't think that will work because both trait Clone and the type Box are not in your crate
one thing you can do is add custom clone method to your trait
and use that
Victor Lopes
@vlopes11
Apr 02 18:30
Let me test
Ingvar Stepanyan
@RReverser
Apr 02 18:30
but you can't combine the real Clone with dynamically dispatched trait
why do you want to clone dynamic object though?
Victor Lopes
@vlopes11
Apr 02 18:41
For example:
trait SomeTrait {}

struct Foo {}
impl SomeTrait for Foo {}
struct Bar {}
impl SomeTrait for Bar {}

struct SomeStruct<'a> {
    some_attr: Vec<Box<'a + SomeTrait>>,
}

impl<'a> SomeStruct<'a> {
    pub fn some_method(&self) -> Vec<Box<SomeTrait>> {
        self.some_attr.clone();
    }
}
Ingvar Stepanyan
@RReverser
Apr 02 18:41
Hmm... maybe better not to clone that data? It's likely to be pretty expensive
I'd instead return &[Box<SomeTrait>] and use it where possible
Victor Lopes
@vlopes11
Apr 02 18:46
Hmm but in case we really need to implement Clone for SomeStruct, we don't have options?
Ingvar Stepanyan
@RReverser
Apr 02 18:47
There are but they're tricky
As I said, one option is to have custom method that would clone anything into such box, and then you can make cloning to work...
And you could probably even separate it out into its own base trait and provide blanket implementation to avoid reimplementing this manually...
Let me try something
So something like this is not pretty, but it works, even with derive(Clone): https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=4e96609149bce63ae5ad428db14413c3
Ingvar Stepanyan
@RReverser
Apr 02 18:52
(you could keep them as a single trait, but then you would have to implement clone_into_dyn_box manually for each implementor of SomeTrait, and I tried to avoid that in favour of derive)
Victor Lopes
@vlopes11
Apr 02 19:01
hmm got it
Thanks for the help!
David O'Connor
@David-OConnor
Apr 02 22:19
@WreckedAvent Thanks. Aborting, and going with only Vec<T> as the API. I'm leaning towards this being intractable. My goal was for a clean, flexible API