These are chat archives for rust-lang/rust

29th
Mar 2019
Brian Knapp
@knappador
Mar 29 00:12
Does Cell move a value off the stack in creation?
matrixbot
@matrixbot
Mar 29 01:09
bspeice No; cells and the objects inside them stay on the stack.
Iulian Rotaru
@mortimr
Mar 29 03:39
From what I understand, you cannot impl an enum variant. What I was trying to do was implement a trait for a enum and only some of its variants. Variants with defined traits would call the appropriate methods, while the others will go to the "fallback" implementation.
What would be my best option to achieve such mechanism ?
Iulian Rotaru
@mortimr
Mar 29 03:49
Yes, just wanted to know if there was a way to do it without the match, by defining different implementations based on the variant calling. But if there is not other option, I'll do it this way
Riley Cat
@WreckedAvent
Mar 29 03:50
what is your use case? you probably shouldn't be thinking of variants of an enum so differently that their implementations would be in different places
Iulian Rotaru
@mortimr
Mar 29 03:54
In my use case I have different types of variables that can interact between each others with operations (like a multiplication let's say). I want to define only the legal cases. Let's say I have types A, B, C & D as different variable types, and multiplication is only allowed on A and D, I'd like to impl for A ... mul(self, rh: B) impl for B ... mul(self, rh: A) but have an impl for Enum ... mul(self, rh: Enum) that will be called and handle illegal cases
but the whole "point" of an enum is you never treat it by its variants; you never specifically request an Ok<T>, only a Result<T, _>, and if you don't need this behavior, you don't need an enum
Iulian Rotaru
@mortimr
Mar 29 03:58
Ok, noted ! thank you for your help
Riley Cat
@WreckedAvent
Mar 29 04:00
in your specific use case I would expect something like
impl Multiplication for A {
  type LegalRhs = B;
  fn mul(self, rhs: Self::LegalRhs) -> ... { ... }
}
if that syntax is unfamiliar to you, consult the rust book
in this case, what you want to do is not have an enum which "handles illegal cases", you want to let the type checker make it so illegal cases don't even compile
Iulian Rotaru
@mortimr
Mar 29 04:09
I can’t do this as it depends on runtime
Riley Cat
@WreckedAvent
Mar 29 04:13
as in, this comes from arbitrary input?
Iulian Rotaru
@mortimr
Mar 29 04:17
yes
(I build an ast from files containing expressions and then execute it, so 100% rely on input)
Riley Cat
@WreckedAvent
Mar 29 04:28
so don't forget about parser combinators like nom here but yeah in that case you'll probably have an enum and a big match expression
Iulian Rotaru
@mortimr
Mar 29 04:29
I'm using pest as I had some experience with peg-like grammar :)
Riley Cat
@WreckedAvent
Mar 29 04:29
that's also fine :slight_smile:
Iulian Rotaru
@mortimr
Mar 29 04:30
oh nice the pattern matching with self
will use that
thanks
Riley Cat
@WreckedAvent
Mar 29 04:32
:thumbsup:
John
@onFireForGod_gitlab
Mar 29 04:42
how does rust handle deadlocks?
can the compiler catch them?
Riley Cat
@WreckedAvent
Mar 29 04:44
it's harder to write dumb parallel code in rust, but not impossible
Norberto Lopes
@nlopes
Mar 29 18:40

Hi everyone. After a discussion with a friend on Traits, I was a bit confused and went down this rabbit hole of what should work and shouldn't work. I think it's odd that this code compiles: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7ecfc72bf57042a1431ea590403ae7a2. This code, doesn't (which makes sense to me): https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e2f9494d5101bbb87c3258f48761ab7f.

Would be forever grateful if someone could point me to the right direction (on why the first one is ok to compile, and if it makes sense)

Zakarum
@omni-viral
Mar 29 19:42
@nlopes when you use trait name where type is expected it is treated as trait object.
Trait object is an unsized type which can be coerced to from any implementation of that trait
In 2018 edition you are encouraged to use dyn keyword for trait objects. Like this: dyn TraitName
Some traits are not object-safe and cannot be used for naming trait object
If trait has static methods, or functions that receive self by value, or functions with template parameters - this trait is not object-safe.
Unless those functions not marked with where Self: Sized bound
Norberto Lopes
@nlopes
Mar 29 19:51
So generally, a impl TraitA on TraitB is allowed in rust? For some reason I assumed it wouldn't.
Ichoran
@Ichoran
Mar 29 20:02
for not on, but generally yes--as long as in all cases where you might have TraitB you can use that implementation for TraitA, why not?
Denis Lisov
@tanriol
Mar 29 20:26
impl TraitA for TraitB is not as interesting as it looks. But the interesting thing, which is impl<T> TraitA for T where T: TraitB, does also work with some limitations on which crates can contain that implementation.
Zakarum
@omni-viral
Mar 29 20:27
impl TraitA on TraitB is actually impl TraitA on dyn TraitB
where dyn TraitB is type of trait-object
See for example std::any::Any all methods except one are implemented for dyn Any, dyn Any + Send, dyn Any + Sync and permutations
Riley Cat
@WreckedAvent
Mar 29 21:01
@Ichoran generally yes. your compiler error has nothing to do with implementing a trait for another trait, which is why everyone is talking about trait objects. if you simply add &self to the function in A, your compile error will go away and things will work as intuition might expect
Ichoran
@Ichoran
Mar 29 21:47
That was @nlopes, not me
Riley Cat
@WreckedAvent
Mar 29 21:48
oh, sorry
Ichoran
@Ichoran
Mar 29 21:48
But the error is because you don't have anything to dispatch on, so it's not unrelated.
It could be explained better in the error message, though.
Victor Lopes
@vlopes11
Mar 29 22:09

Hello Rustaceans, good evening. If I do something like this

use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::thread;

struct SomeStruct<'a> {
    phantom: PhantomData<&'a ()>,
}

struct UpperStruct<'a> {
    somearc: Arc<Mutex<SomeStruct<'a>>>,
}

impl<'a> UpperStruct<'a> {
    fn another_method(&mut self) {
        let data = Arc::clone(&self.somearc);
        thread::spawn(move || {
            let mut data = data.lock().unwrap();
        });
    }
}

fn main() {}

then I receive this

error[E0477]: the type `[closure@src/main.rs:16:23: 18:10 data:std::sync::Arc<std::sync::Mutex<SomeStruct<'a>>>]` does not fulfill the required lifetime
  --> src/main.rs:16:9
   |
16 |         thread::spawn(move || {
   |         ^^^^^^^^^^^^^
   |
   = note: type must satisfy the static lifetime

Doing some research I came in contact with crossbeam crate from 2016. Is there any standard or more recent alternative solution for that?

Of course, this works normally:
use std::marker::PhantomData;
use std::sync::{Arc, Mutex};
use std::thread;

struct SomeStruct<'a> {
    phantom: PhantomData<&'a ()>,
}

struct UpperStruct<'a> {
    //somearc: Arc<Mutex<SomeStruct<'a>>>,
    somearc: Arc<Mutex<bool>>,
    phantom: PhantomData<&'a ()>,
}

impl<'a> UpperStruct<'a> {
    fn another_method(&mut self) {
        let data = Arc::clone(&self.somearc);
        thread::spawn(move || {
            let mut data = data.lock().unwrap();
        });
    }
}

fn main() {}
Denis Lisov
@tanriol
Mar 29 22:13
What do you want to do? Spawn a couple of threads and wait in this method until all of them are done?
Riley Cat
@WreckedAvent
Mar 29 22:14
does SomeStruct own the PhantomData? iirc you could get rid of the errors easily by sticking it in a box
Victor Lopes
@vlopes11
Mar 29 22:17
@tanriol smth like that. Actually the arc borrow will last for a very small fraction of the thread
@WreckedAvent yep, SomeStruct owns the data with the given lifetime. But if you somearc: Arc<Mutex<Box<SomeStruct<'a>>>>, we still have the same situation
Riley Cat
@WreckedAvent
Mar 29 22:18
no no, I meant box in SomeStruct
gets rid of the life time pollution too
Victor Lopes
@vlopes11
Mar 29 22:22
@WreckedAvent Oh, the PhantomData is just a minimal example. I actually need to put some stuff with a specified lifetime inside SomeStruct. For that, I'm forced also to declare the lifetime for UpperStruct, which causes this problem with the threads
Denis Lisov
@tanriol
Mar 29 22:25
Yes, if you're fine with that, crossbeam scoped threads that are guaranteed to exit before the function returns are a good option.
On the other hand: why do you need threads here?
Victor Lopes
@vlopes11
Mar 29 22:25
@tanriol The final goal is to handle some jsonrpc calls asynchronously
@tanriol Oh, I see. So crossbeam is an nowadays option. Ok, thanks, I'll do the test :)
Denis Lisov
@tanriol
Mar 29 22:26
In a year I'd probably suggest the async/futures ecosystem, but for now it has its share of lifetime problems.
An interesting option, usually used for CPU-bound tasks but not limited to them, is to use rayon
I'd have a look, but my guess is crossbeam is a better fit for this task.
And yes, the latest crossbeam release is just two months old.
Victor Lopes
@vlopes11
Mar 29 22:37
@tanriol very good, thank you very much :)