These are chat archives for rust-lang/rust

12th
Apr 2017
Marcin Jurczuk
@MrSpock
Apr 12 2017 08:53
Hello
@tike - I've solved this problem :)
Sometime writing allos you to define problem differently in your head ans solution pops-up :)
But I stumble upon lifetime fith :/
Anyone able to help
Denis Lisov
@tanriol
Apr 12 2017 08:54
What's the problem?
Marcin Jurczuk
@MrSpock
Apr 12 2017 08:55
I need to implement trait so I can use all struct that implement that as a element of struct
here is code
And all my attempts all failed
struct A can take any struct as handler that fulfills Handler trait
I've tried all possible options for putting life time markers and still cant get code to compile :/
last two errors looks like one is oposite of another :)
I just updated gist
there was second error missing
Simple code composition and can't make it work :/
Marcin Jurczuk
@MrSpock
Apr 12 2017 09:03
I'm be back here in next 2-3 hrs. Another task is waiting :)
Denis Lisov
@tanriol
Apr 12 2017 09:05
Not trivial... I'm not sure that you actually can have it that way.
The 'a lifetime that's used for output only looks suspicious to me.
Denis Lisov
@tanriol
Apr 12 2017 09:13
I'd suggest that the most appropriate signeture for Handler::handle would be fn handle(&self, s: &str) -> String
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:29
Hi
With String as output it easy
:)
Denis Lisov
@tanriol
Apr 12 2017 11:31
...and as soon as you need &str, you need to know the answer to the first question: who owns the data?
Your gist's impl had this mistake: you can't create a new String with format!, return a reference to it and... oops, who's supposed to free it and when, actually?
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:34
So you suggest I should create variable befor returning it ? It shold be destroyed/freed when structure that have ref to it is deallocated
I see that that the moment where instance of struct A is not needed all references to other objects that are used by this struct (also via references) should be freed
Vladimir
@Crazy-Owl
Apr 12 2017 11:36
at any given moment any pointer should reference "alive" data
that means it's stored somewhere
Denis Lisov
@tanriol
Apr 12 2017 11:36
First, in your gist you were taking self by value, so A was deallocated right after the call.
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:37
Changeing self to &self doesn't help. Tried that
Denis Lisov
@tanriol
Apr 12 2017 11:38
If you want to create a String, store it somewhere in A and return a reference to it, the signature should probably be fn handle(&mut self, &str) -> &str;
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:40
I don't want to store anything inside struct A. What I wan't it to use struct as a containter for group of functions. And one of those functions should return &str.
Vladimir
@Crazy-Owl
Apr 12 2017 11:40
You can make it fn handle(self, s: &'a String) -> &'a str
have you tried that?
that way you don't need any lifetime parameters and your return values should be alive for as long as s arg is alive
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:41
I tried fn handle(self, s: &str) -> &str signature and error is in exact the same place. Let me check that
Vladimir
@Crazy-Owl
Apr 12 2017 11:41
ouch. &'a str of course
and change self to &self
you're basically destroying self struct after handle call
but that has been mentioned already
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:44
impl<'a> Handler<'a> for TestHandle {
fn handle(&self, s: &'a str) -> &'a str {
let r = format!("via {}", s);
&r
}
}
with such code I'm getting error that r is not live enough
How to mark r life time ?
Vladimir
@Crazy-Owl
Apr 12 2017 11:44
format! creates a new object, which you store at r
Denis Lisov
@tanriol
Apr 12 2017 11:44
Once more, you cannot create a String and return a reference to its contents without keeping it in some permanent place.
Vladimir
@Crazy-Owl
Apr 12 2017 11:45
then when you exit handle, r is destroyed
thus &r is no longer valid
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:45
ok. but how to tell compiler that it shout keep r until TestHandle struct is existing ?
Vladimir
@Crazy-Owl
Apr 12 2017 11:45
r is stored on stack
you should return an owned object
like String as @tanriol suggested
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:46
Hah - yes -
string pointers in Rust are a nightmare :)
Vladimir
@Crazy-Owl
Apr 12 2017 11:46
why is &str necessary for your code?
they're just like other pointers
you have to keep in mind where data comes from and where data is stored
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:47
I wanted to avoid return String since this text will be used very very often by other functions and I wanted to avoid copying it constantly
So maybe I will return String and in another part of code just return & to that string
Vladimir
@Crazy-Owl
Apr 12 2017 11:47
yes
you can call handle, store String somewhere
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:47
But then I'm afraid problem pops-up in another place of code ;)
Vladimir
@Crazy-Owl
Apr 12 2017 11:47
and then use reference to that string
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:47
with exact the same problem :)
Vladimir
@Crazy-Owl
Apr 12 2017 11:47
how so?
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:48
Ok - thanks - I will refactor code to using String and see if this will be ok
Argh ..
problem stil in the same place
struct A<'a, S>
where S: Handler
{
name: String,
handler: Box<S>,
}
Vladimir
@Crazy-Owl
Apr 12 2017 11:51
what do you need 'a for in this code?
there are no reference fields in your struct
(anymore)
Denis Lisov
@tanriol
Apr 12 2017 11:51
You can have something like this
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:51
Ok ! code compiled :)
After remove of all lifetime markers
Yes! :)
It works with Strings
Vladimir
@Crazy-Owl
Apr 12 2017 11:52
just as it should
you can refactor it to be more efficient later if the need arises
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:53
Rule #1 of Rust should be "don't use &str" if you don't have to :)
Denis Lisov
@tanriol
Apr 12 2017 11:53
So it's possible to make this work with references if really needed, but not worth it.
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:55
Ok - thanks !
Denis Lisov
@tanriol
Apr 12 2017 11:55
Well, not exactly. I'd say "don't try to use &str for the strings you're creating".
Vladimir
@Crazy-Owl
Apr 12 2017 11:56
Rule #1: Don't panic!
Marcin Jurczuk
@MrSpock
Apr 12 2017 11:56
:P
gavynriebau
@gavynriebau
Apr 12 2017 12:00
Anyone know what am I missing here / how can I return a file as &T?
use std::fs::File;
use std::io::{Write, Read, Seek, BufReader};

fn TestReturningGenericType<'a, T : Read + Seek>() -> &'a T {
    let file = File::open("test.txt").unwrap();

    &file as &T
}
error: non-scalar cast: `&std::fs::File` as `&T`
  --> src/main.rs:12:5
   |
12 |     &file as &T
   |     ^^^^^^^^^^^
Vladimir
@Crazy-Owl
Apr 12 2017 12:01
looks like you have the same problem
file itself is not stored anywhere and won't live long enough
it will be destroyed as soon as TestReturningGenericType exits
but the message is unrelated to that fact
also I'm not sure that as will help you here
what are you trying to achieve?
Why isn't returning File object (which satisfies both trait boundaries afaik) enough?
gavynriebau
@gavynriebau
Apr 12 2017 12:05
I want to be able to pass around a &T (known to implement Read + Seek) which could either be a file or a reference to a stdin.
Vladimir
@Crazy-Owl
Apr 12 2017 12:05
hm
you can just pass a reference to file or reference to stdin to everyone who needs &T
&File will satisfy &T where T: Read + Seek
or you could Box it
I'm not sure that you can just
let x: Box<T: Read + Seek> = File::open ...
Jonas Platte
@jplatte
Apr 12 2017 12:09
@gavynriebau What type parameters do is let the user choose a concrete type to call the function with. Converting a File to an arbitrary type implementing Read + Seek is not possilble.
I think what you want is an existential instead (hiding the fact that what you are returning is a File, instead just specifying that is is some type that implements Read + Seek), right?
gavynriebau
@gavynriebau
Apr 12 2017 12:11
I think so yes, is that possible in rust?
Jonas Platte
@jplatte
Apr 12 2017 12:11
It depends ^^
If you want full-blown existentials, no. If you just want to return an existential, you can do that on nightly, and there are some restrictions to it.
However, you can also use Box instead of generics, which would mean dynamic dispatch, but works on stable.
The nightly solution with static dispatch would be something like
#![feature(conservative_impl_trait)]

fn foo() -> impl Read + Seek {
    File::open("test.txt").unwrap()
}
The stable solution with dynamic dispatch would be something like
fn foo() -> Box<Read + Seek> {
    Box::new(File::open("test.txt").unwrap())
}
(both just off the top of my head, I might have gotten bits of it wrong)
Vladimir
@Crazy-Owl
Apr 12 2017 12:18
error[E0225]: only Send/Sync traits can be used as additional traits in a trait object
 --> test.rs:6:24
  |
6 | fn foo() -> Box<Read + Seek> {
  |                        ^^^^ non-Send/Sync additional trait

error: aborting due to previous error
Seek is not Send/Sync apparently
And Read too
Jonas Platte
@jplatte
Apr 12 2017 12:23
Huh, so it actually doesn't (generally) work with multiple traits. SO confirms: http://stackoverflow.com/a/35878196/1592377
I just never tried to do that I guess. Also I don't have a problem running nightly, but I'm not entirely sure if impl trait is different in this regard. (I'd assume it is)
Vladimir
@Crazy-Owl
Apr 12 2017 12:29
this works on stable:
trait Foo : Seek + Read {}

impl<T> Foo for T where T: Seek + Read {}

fn foo() -> Box<Foo> {
    Box::new(File::open("test.txt").unwrap())
}
just as SO tell us - just a bit of workaround
gavynriebau
@gavynriebau
Apr 12 2017 12:39
@Crazy-Owl @jplatte I'm still very new to rust so it's really nice that you both took the time to help me with this, thanks very much!
Vladimir
@Crazy-Owl
Apr 12 2017 12:40
you're welcome
Jonas Platte
@jplatte
Apr 12 2017 12:41
happy to help! :)
Jakub Kozlowski
@jkozlowski
Apr 12 2017 21:29
I was wondering if anyone would be able to help, I have been banging my head on this for a bit; I want to have a thread local Reactor (from https://github.com/jkozlowski/tokio-smp/blob/master/src/reactor/mod.rs) that I can initialize once for each thread just after starting it; the whole point is to be able to have a &'static Reactor that I can hand around. I know that this is probably terribly unsafe (and global state is awful in general), but I am trying to port https://github.com/scylladb/seastar to rust and that is how they do it. It is possible that I am terribly misunderstanding something, I am still new to rust. I tried to figure it out using state::LocalStorage, scoped_thread_local etc., resorting to Unique but nothing seems to click
Denis Lisov
@tanriol
Apr 12 2017 21:34
thread_local!?
Jakub Kozlowski
@jkozlowski
Apr 12 2017 21:37
the with method gives you a normal '&' reference not &'static. Maybe I'm misunderstanding what I want, I'll try again
Denis Lisov
@tanriol
Apr 12 2017 21:37
Or is the idea that you want to have a reactor constantly running on that thread?
Jakub Kozlowski
@jkozlowski
Apr 12 2017 21:39
I basically start n threads and there is going to be a reactor on each. I can then send futures to each and they should be somehow able to pull out the reference to the local reactor
I think I'll try again tomorrow, maybe I'll figure it out. Maybe I just think that I need a &'static Reactor, but maybe just a normal reference is fine, in which case it will work with thread_local
Denis Lisov
@tanriol
Apr 12 2017 21:41
Have you already seen tk-easyloop?
Jakub Kozlowski
@jkozlowski
Apr 12 2017 21:41
I haven't, I'll have a look!
sounds like what I want, I'll study the code and come back if it doesn't help. Thanks a lot!