These are chat archives for rust-lang/rust

18th
May 2016
fstuess
@fstuess
May 18 2016 07:48
@SCareAngel Ok. Hmm. Thx.
nishidy
@nishidy
May 18 2016 14:02
Hi, I have a problem understanding &str and String.

use std::thread;
use std::sync::mpsc;
//use std::io;

fn call<'a>(txt:&'a str, tx1: &mpsc::SyncSender<&'a str>){
tx1.send(txt.clone()).unwrap();
}

fn main() {

let mut txt = "abc";
//let mut txt = String::new();
//io::stdin().read_line(&mut txt);

let (tx1,rx1) = mpsc::sync_channel(1);
let (tx2,rx2) = mpsc::sync_channel(1);

thread::spawn(move||{
    for _ in 0..2 {
        let rtext = rx1.recv().unwrap();
        println!("{}",&rtext);
    }   
    tx2.send(()).unwrap();
}); 

call(&txt,&tx1);

//txt = "xyz".to_string();
txt = "xyz";

call(&txt,&tx1);

rx2.recv().unwrap();

}

Zakarum
@omni-viral
May 18 2016 14:03
@nishidy and the problem is...?
nishidy
@nishidy
May 18 2016 14:03
ok, let me write now
This program works fine
Zakarum
@omni-viral
May 18 2016 14:04
Yea. I checked it already )
nishidy
@nishidy
May 18 2016 14:04
but actually i rather want to run the code with the commented-out lines
You can see that I intentionally leave the comments
Those are what I want to run actually
Zakarum
@omni-viral
May 18 2016 14:05
io::stdin().read_line expect &mut String as first argument
nishidy
@nishidy
May 18 2016 14:05
I thinks this problem comes form the difference between &str and String
Zakarum
@omni-viral
May 18 2016 14:05
So you should create one
nishidy
@nishidy
May 18 2016 14:05
in my understanding
ok
ya
Zakarum
@omni-viral
May 18 2016 14:05
str ~ String is like [T] ~ Vec<T>
nishidy
@nishidy
May 18 2016 14:06
okey
Zakarum
@omni-viral
May 18 2016 14:06
You can get &str from String
You can create String from &str by cloning all characters into it
But you can't use plain String where &str is required and vice versa
nishidy
@nishidy
May 18 2016 14:08
I don't think it is the problem here
Zakarum
@omni-viral
May 18 2016 14:08
Yeap
You have a lifetime problem
nishidy
@nishidy
May 18 2016 14:08
i think so
Zakarum
@omni-viral
May 18 2016 14:08
&txt is not &'static String
Erik Hedvall
@Ogeon
May 18 2016 14:08
The problem is that threads may outlive main, so you can't send references to things in main since those things may get destroyed
before the thread ends
Zakarum
@omni-viral
May 18 2016 14:09
You should either
  1. send copies, not the references
  2. share via Arc
Erik Hedvall
@Ogeon
May 18 2016 14:09
Your current program uses &'static str, and 'static is valid for the whole program.
nishidy
@nishidy
May 18 2016 14:09
  1. does not work, either. I think.
I tried clone() but did not work.
in call fn.
for txt
Erik Hedvall
@Ogeon
May 18 2016 14:10
clone on a &'a str will just create a new &'a str.
Zakarum
@omni-viral
May 18 2016 14:10
use std::thread;
use std::sync::mpsc;
use std::io;

fn call<'a>(txt:&'a String, tx1: &mpsc::SyncSender<String>){
tx1.send(txt.clone()).unwrap();
}
fn main() {
let mut txt = String::new();
io::stdin().read_line(&mut txt);

let (tx1,rx1) = mpsc::sync_channel(1);
let (tx2,rx2) = mpsc::sync_channel(1);

thread::spawn(move||{
    for _ in 0..2 {
        let rtext = rx1.recv().unwrap();
        println!("{}",&rtext);
    }   
    tx2.send(()).unwrap();
}); 

call(&txt,&tx1);

txt = "xyz".to_string();

call(&txt,&tx1);

rx2.recv().unwrap();
}
nishidy
@nishidy
May 18 2016 14:10
oh, lifetime is the same
Zakarum
@omni-viral
May 18 2016 14:10
Work with clone
nishidy
@nishidy
May 18 2016 14:11
I expected the clone have the different lifetime then
Erik Hedvall
@Ogeon
May 18 2016 14:11
You are making a clone of a reference, and not the source
nishidy
@nishidy
May 18 2016 14:11
oh
ok
*txt.clone()?
Erik Hedvall
@Ogeon
May 18 2016 14:12
You have to do as @SCareAngel suggests, or use to_string or to_owned
nishidy
@nishidy
May 18 2016 14:12
ok
Erik Hedvall
@Ogeon
May 18 2016 14:12
...or into
but your channel has to send something else than &'a str, since 'a is tied to the main function
nishidy
@nishidy
May 18 2016 14:13
Understood.
Let me check @ScareAngel's code
oh, I did not call unwrap() for the clone method
Erik Hedvall
@Ogeon
May 18 2016 14:15
It's for send
nishidy
@nishidy
May 18 2016 14:15
That's why I did not think clone work
It is actually Send, right?
Zakarum
@omni-viral
May 18 2016 14:16
String is Send
nishidy
@nishidy
May 18 2016 14:16
good
um, no no
Zakarum
@omni-viral
May 18 2016 14:17
Also call can be rewritten as
fn call<'a>(txt:&'a str, tx1: &mpsc::SyncSender<String>){
     tx1.send(txt.to_string()).unwrap();
}
And I think it is better version
nishidy
@nishidy
May 18 2016 14:22
ok, this part
tx1: &mpsc::SyncSender<String>
nishidy
@nishidy
May 18 2016 14:29
why do you think String's clone() works but &str's clone() does not? As @Ogeon says, String's clone copies source of it and &str's clone only copies of reference and the lifetime is kept?
Erik Hedvall
@Ogeon
May 18 2016 14:30
That's exactly why. clone is specified to always return the same type as what's cloned.
When calling clone on a &str, you would either get a &str or a str, and str can't be instantiated without some kind of pointer.
Zakarum
@omni-viral
May 18 2016 14:31
@nishidy your tx1 was SyncSender<&'a str> That was a main problem
nishidy
@nishidy
May 18 2016 14:32
umm. So &str seems strange now in terms of having &.
Zakarum
@omni-viral
May 18 2016 14:32
Also you can't clone str cause it is ?Sized
But &str can be clonned
That what was happen in your example
nishidy
@nishidy
May 18 2016 14:33
This message was deleted
fn call<'a>(txt:&'a String, tx1: &mpsc::SyncSender<String>){
tx1.send(txt.clone()).unwrap();
}
Zakarum
@omni-viral
May 18 2016 14:34
btw, you can edit your messages
nishidy
@nishidy
May 18 2016 14:34
ok
found it. thanks
Zakarum
@omni-viral
May 18 2016 14:35
Do you have any more questions?
nishidy
@nishidy
May 18 2016 14:35
txt:&'a String
here we have & for String
but txt.clone() works
on the other hand
in my first pasted code
Zakarum
@omni-viral
May 18 2016 14:35
cause of the signature Clone::clone(&self)
nishidy
@nishidy
May 18 2016 14:35
fn call<'a>(txt:&'a str, tx1: &mpsc::SyncSender<&'a str>){
tx1.send(txt.clone()).unwrap();
}
txt:&'a str
Zakarum
@omni-viral
May 18 2016 14:36
Yeap
nishidy
@nishidy
May 18 2016 14:36
here we have also & for str
what's the difference??
Zakarum
@omni-viral
May 18 2016 14:36
But str is not Clone
so there is no str::clone function
Erik Hedvall
@Ogeon
May 18 2016 14:36
The important difference is str vs String
nishidy
@nishidy
May 18 2016 14:37
right!
Zakarum
@omni-viral
May 18 2016 14:37
But compiler found that there is &T::clone function that returns copy of the reference
Erik Hedvall
@Ogeon
May 18 2016 14:37
...and &mpsc::SyncSender<&'a str> vs &mpsc::SyncSender<String>
nishidy
@nishidy
May 18 2016 14:38
i understand about it . that's what I wanted to have. i mean remove 'a from syncsender
because it is sent to thread which can outlive main
otherwise i need to clone the string
in either way, the lifetime should be different
Erik Hedvall
@Ogeon
May 18 2016 14:39
As @SCareAngel said, &T implements Clone, but str doesn't. &str is &T where T = str
Zakarum
@omni-viral
May 18 2016 14:39
It should be 'static
nishidy
@nishidy
May 18 2016 14:40
ok... important here is about str vs String, not &str vs String
Zakarum
@omni-viral
May 18 2016 14:40
For std::thread::spawn you can only pass something that 'static
nishidy
@nishidy
May 18 2016 14:41
that's why we need move to pass environments, right?
Zakarum
@omni-viral
May 18 2016 14:41
yeap
nishidy
@nishidy
May 18 2016 14:41
ok
ok, in correct code, we cloned on the source of txt of String, but what if we want to clone the reference to it?
Erik Hedvall
@Ogeon
May 18 2016 14:43

In

fn call<'a>(txt:&'a String, tx1: &mpsc::SyncSender<String>){
    tx1.send(txt.clone()).unwrap();
}

the compiler can choose between <&String>::clone -> &String and String::clone -> String, but sees that send wants a String, so it picks the latter.

nishidy
@nishidy
May 18 2016 14:45
oh!
Erik Hedvall
@Ogeon
May 18 2016 14:46
That's why it just worked
nishidy
@nishidy
May 18 2016 14:46
compiler infers which one I need by clone() from here, SyncSencder<String>?
Zakarum
@omni-viral
May 18 2016 14:47
To be more precise. From SendSync<T>::send(T)
nishidy
@nishidy
May 18 2016 14:47
interesting...
ok
Zakarum
@omni-viral
May 18 2016 14:47
But I should check
Erik Hedvall
@Ogeon
May 18 2016 14:47
That's correct
Zakarum
@omni-viral
May 18 2016 14:48
No
nishidy
@nishidy
May 18 2016 14:48
No?
Zakarum
@omni-viral
May 18 2016 14:48
fn foo(_: &String) {}

fn main() {
    let x = String::new();
    foo(x.clone());
}
This doesn't compile
Wait.
Erik Hedvall
@Ogeon
May 18 2016 14:49
That's because x is String. Try (&x).clone()
Zakarum
@omni-viral
May 18 2016 14:49
fn foo(_: &String) {}

fn main() {
    let x = String::new();
    let y = &x;
    foo(y.clone());
}
This also
The compiler always choose String::clone
Because it is String is Clone
Erik Hedvall
@Ogeon
May 18 2016 14:50
wait, what?
Zakarum
@omni-viral
May 18 2016 14:50
struct NotClone;

fn foo(_: &NotClone) {}

fn main() {
    let x = NotClone;
    let y = &x;
    foo(y.clone());
}
This does compile!
Because NotClone isn't Clone
That is. If T and &T have method foo then for t.foo() where t: &T T::foo will be called
Erik Hedvall
@Ogeon
May 18 2016 14:53
Oh, it could be that the compiler tries to dereference first. I.e. first (*x).clone() then (x).clone(). It does stuff like that
It will add as many dereferences as necessary to make things work
Zakarum
@omni-viral
May 18 2016 14:53
it seems so
Erik Hedvall
@Ogeon
May 18 2016 14:54
...so if it finds clone for *x, it will consider the work done
Zakarum
@omni-viral
May 18 2016 14:55
iteresting. It doesn't try to dereference twice before check type itself

fn foo(_: &isize) {}


fn main() {
    let x = 1isize;
    let y = &&x;
    foo(y.clone());
}
This work
I think this is so because of &self in clone signature
So calling T::clone for t.clone() where t: &T doesn't require dereferensing or adding references
You see. It can be rewiritten as such T::clone(t)
In the case T: !Clone it have to add one level of reference and call &T::clone(&t)
Erik Hedvall
@Ogeon
May 18 2016 14:59
That's what it does, as far as I know
I don't remember the exact behavior, but I think it may references once, but may dereference as many times as necessary to find a method
Zakarum
@omni-viral
May 18 2016 15:01
But it would not remove rerefences. If t: &&T then it will call &T::clone(t) and that's all
Erik Hedvall
@Ogeon
May 18 2016 15:02
That's because it found <&T>::clone(*t) and seemed to stop there
Zakarum
@omni-viral
May 18 2016 15:02
No. not <&T>::clone(*t)
Erik Hedvall
@Ogeon
May 18 2016 15:02
Sorry, I mixed things up
Your example will work, no matter how many & you add, because &&T is coerced into &T
Zakarum
@omni-viral
May 18 2016 15:05
I mean that for &(n-times)T it always will choose &(n-1 times)T::clone
Unless n == 1 and T: !Clone
Erik Hedvall
@Ogeon
May 18 2016 15:10
I'm trying to find the exact rules, instead of guessing, and this StackOverflow answer is the closest to a summary I have gotten: http://stackoverflow.com/a/28552082
Zakarum
@omni-viral
May 18 2016 15:17
UFCS makes things clearer
Erik Hedvall
@Ogeon
May 18 2016 15:24
So the way I understand it is that it will first check if T matches one of self, &self or &mut self, and then start dereferencing.

&&&&&X, this doesn't match either step (the trait isn't implemented for &&&&X or &&&&&X), so we dereference once to get U = &&&&X, which matches 1 (with Self = &&&X) and the call is RefM::refm(*foo)

This may explain the loss of one reference in your last example

Erik Hedvall
@Ogeon
May 18 2016 15:29
Interesting how it can be both confusing, but still quite intuitive to work with (except for edge cases). Anyway, got to go
nishidy
@nishidy
May 18 2016 15:45
try!(io::stdin().read_line(&mut txt)); Compiler does not allow this, saying try! expects () but found Result<_,_>. Why? read_line() should return Result, right?
Zakarum
@omni-viral
May 18 2016 16:03
@nishidy what does return function this line in?
I guess it returns ()
And try! tries to return Result<_, _>
nishidy
@nishidy
May 18 2016 16:09
oh, I thought that try! unwraps Result. it's wrong?
Zakarum
@omni-viral
May 18 2016 16:10
It unwraps only Ok
And return if there is Err(_)
Almost unchaning
nishidy
@nishidy
May 18 2016 16:11
you mean unchaining?
Zakarum
@omni-viral
May 18 2016 16:12
try!(expr) expands to
match expr {
    Ok(ok) => ok,
    Err(err) => { return Err(From::from(err)) }
}
So if your expr have type Result<_, E1> then function should have return type Result<_, E2>, where E2: From<E1>
Or just Result<_, E1> since T: From<T> for all T
So your function should have type Result<_, std::io::Error>
Or Result<_, YourCoolError> and YourCoolError should implement From<std::io::Error>
woops. There was a little mistake in example, sorry. Now it's fixed.
nishidy
@nishidy
May 18 2016 16:57
Thanks