These are chat archives for rust-lang/rust

8th
May 2017
#[macro_use]
extern crate gc_derive;
extern crate gc;

use gc::Gc;

#[derive(Trace, Finalize)]
struct Foo {
    x: Gc<Foo>,
    y: u8,
    // ...
}
how do you construct Foo if you need a Foo first?
Frank McSherry
@frankmcsherry
May 08 2017 06:44
@bombless It is probably similar to a linked list, where struct Foo { next: Option<Box<Foo>> }; I'm guessing there is a constructor for Gc<Foo> that doesn't need a Foo. Or "hoping", let's say.
Actually, reading the docs it doesn't look like that at all. Maybe it is a bad example. I'll see if I can ask manishearth (or, check out #rust on irc; a bit livelier)
Frank McSherry
@frankmcsherry
May 08 2017 06:54
Chit-chat on #rust suggests it is a readme.md bug. Not from the crate author though. Perhaps file an issue? :D
Imagine the example uses either an Option<Gc<Foo>> or a Gc<Option<Foo>>.
Frank McSherry
@frankmcsherry
May 08 2017 07:05
Ah, I went and did it: Manishearth/rust-gc#53
Ashley Mannix
@KodrAus
May 08 2017 07:30
@frankmcsherry doing the needful :smiley:
Michael Thomas
@Michaelt293
May 08 2017 07:45
Inside a module, do I have to use the pub keyword for everything I want public? Data types/functions etc?
Sherzod Mutalov
@shmutalov
May 08 2017 07:49
Can anyone suggest how to make following function less verbose:
And, how to not clone url?
Frank McSherry
@frankmcsherry
May 08 2017 08:04
@shmutalov Maybe check out the AsRef trait? It is like Into, but instead of producing owned data it produces a reference. It looks like search_rooms only uses a references to the cloned String, and so this might work?
Denis Lisov
@tanriol
May 08 2017 11:19
@shmutalov Keeping the API, something like the following?
pub fn get_room_id<S>(&self, uri: S) -> ApiResult<String>
    where S: Into<String>
{
    let url = uri.into();
    let url2 = url.clone();

    self.search_rooms(url)?
        .rooms
        .iter()
        .find(|r| r.uri.as_ref().map_or(false, |x| x == &url2))
        .ok_or(ApiError::RoomNotFound)
}
Frank McSherry
@frankmcsherry
May 08 2017 12:46
I would guess that you could replace a lot of the S: Into<String> with S: AsRef<str>. If you do the same thing on search_rooms you wouldn't need to uri.into(), nor get a second copy because you lost ownership of url when you sent it to search_rooms.
Ahaha, you've done that, I think (at least, I clicked your link to check out the old version, and it looks good now).
Wait, no. You call
let uri = uri.as_ref();
self.search_rooms(uri.to_string())?
.rooms.iter()
.find(|r| r.uri.as_ref().map_or(false, |u| u == uri))
.map(|r| r.id.to_string())
.ok_or(ApiError::RoomNotFound)
where I think you could change search_rooms similarly, and just pass &urito it.
Masaki Hara
@qnighy
May 08 2017 13:06
Hi everyone! Do you think the comment here https://github.com/rust-lang/rust/blob/1.17.0/src/librustc_typeck/check/op.rs#L504-L507 is still true? I doubt that, because I couldn't find SIMD types in stdlib nor find SIMD types in other crates which implement PartialEq.
Sherzod Mutalov
@shmutalov
May 08 2017 13:07
@frankmcsherry I specially made all "string" parameters in api methods Into<String>, because, I want that "user" able to pass either &str or String or something else that can be converted to String. Yeah, I am newbie, I thought that I can use AsRef (I doesnt know how that trait works totaly), but "any" string must be copied, because it will be serialized or passed as part of url
@frankmcsherry You are not first saying that it will better to change Into's to AsRef's... Maybe I must listen you both and change the api
Frank McSherry
@frankmcsherry
May 08 2017 13:08
@shmutalov You could also use AsRef<str> where possible. Both &str and String implement it, which is great.
Sherzod Mutalov
@shmutalov
May 08 2017 13:08
Will be api calls faster then (cause only refernece wihtout coping will used)?
shmutalov @shmutalov saying sorry for his english :P
Frank McSherry
@frankmcsherry
May 08 2017 13:10
@shmutalov generally they will be more efficient, because they can avoid allocating copies of strings when you don't actually need to copy them. If you just need to look at the string, then AsRef<str> is a great way to indicate that. On the other hand, Into<String> is how you say "I need to be able to make you into an allocated and owned String that is now mine.
Sherzod Mutalov
@shmutalov
May 08 2017 13:11
@frankmcsherry Ok, thanks. I will test it later. :)
Frank McSherry
@frankmcsherry
May 08 2017 13:11
There may be times where you need Into<String>, if it is important for you to get an actual copy of the string for some reason. However, it looks like a lot of your uses are taking a &String and using it to build up a query string elsewhere. I think many of these cases don't require an owned string (as you will be building a new query string anyhow), and could use a reference instead, saving on the allocations.
Sathya Narrayanan
@sourcepirate
May 08 2017 14:09

I am a new to rust . I have been trying to implement a stack in rust i came up with the below implementation

#[derive(Debug)]
struct Node<T>{
    data: T,
    next: Option<Box<Node<T>>>
}

#[derive(Debug)]
struct List<T> {
    head: Option<Box<Node<T>>>
}

impl<T> List<T> {
    fn new() -> List<T>{
        List{head: None}
    }

    fn push(&mut self, elem: T) {
        let h: Box<Node<T>> = Box::new(Node{
            data: elem,
            next: self.head.take()
        });
        self.head = Some(h);
    }

    fn pop(&mut self) -> Option<T> {
        match self.head.take() {
            None => None,
            Some(head) => {
                let mut uw : Node<T> = *head;
                self.head = uw.next.take();
                Some(uw.data)
            }
        }
    }
}

fn main(){
    let mut lst :List<i32> = List::new();
    lst.push(23);
    lst.push(34);
    lst.push(43);
    lst.push(45);
    println!("{:?}", lst);
    lst.pop();
    println!("{:?}", lst);
}

Is this a good implementation. Can anyone give feedback on it ?

Fra ns
@snarf95_twitter
May 08 2017 14:13
its not bad but likely to be memory-fragmented
Sathya Narrayanan
@sourcepirate
May 08 2017 14:14
Thanks @snarf95_twitter . Could you expain me the issue ??
Fra ns
@snarf95_twitter
May 08 2017 14:16
I'm a newbie to rust aswell but not programming in general... I've actually never tried implementing a linked-list but I imagine it being difficult to get right in terms of performance
like I said, your implementation is fine, but is going to cause memory-fragmentation.
Sathya Narrayanan
@sourcepirate
May 08 2017 14:18
Do you think it is due to Option<Box<Node<T>>> as head
Fra ns
@snarf95_twitter
May 08 2017 14:22
no thats not it
it's more of a problem in node struct tho
what do you need it for?
Sathya Narrayanan
@sourcepirate
May 08 2017 14:28
@snarf95_twitter I have been studying about ownership and borrowing in rust. But i have only the theoritical model in mind. I wanted to know whether in any cases the above code will create a issue.
Sherzod Mutalov
@shmutalov
May 08 2017 14:28
It is memroy fragmented because it is linked list. Allocator will not guarantee that your nodes will placed linear
Sathya Narrayanan
@sourcepirate
May 08 2017 14:29
Thanks @shmutalov .
I have been reading this article.
http://lukaskalbertodt.github.io/2015/10/09/building-an-sql-database-with-10-rust-beginners.html
after reading this i really got interested in learning rust
Fra ns
@snarf95_twitter
May 08 2017 14:32
it's only going to be an issue depending on your requirements for performance lol
you can probably find a cargo with real nice perf
Sathya Narrayanan
@sourcepirate
May 08 2017 14:32
Oh ok @snarf95_twitter thanks for giving a feedback
Serhii Plyhun
@snuk182
May 08 2017 15:01
interesting feature of impl TheTrait for AnotherTrait https://is.gd/rAo2MS
it allows using the TheTrait's functions for AnotherTrait-objects, but not for the impl struct
was this done by intention or by mistake? :smile: any single mention of this neither in book nor in google (well, goo says it does not compile)
Sathya Narrayanan
@sourcepirate
May 08 2017 15:05
Interesting
Serhii Plyhun
@snuk182
May 08 2017 15:14
Denis Lisov
@tanriol
May 08 2017 15:22
@snuk182 Maybe use impl<T: Foo + ?Sized> Bar for T?
Serhii Plyhun
@snuk182
May 08 2017 15:24
No no. I know how it is correct. I wanne know why stuff above works
Especially for to KO stuff. The static requirement accepts non static var
Denis Lisov
@tanriol
May 08 2017 15:38
Seems that impl Bar for Foo is interpreted as impl Bar for Foo + 'static
If I replace it with impl<'a> Bar for Foo + 'a, everything works...
Serhii Plyhun
@snuk182
May 08 2017 15:45
I aint look for the solution. I wanna know if it is a) bug, b) undocumented feature, c) anything else. Should I use it constantly? Why the parameter requires static? Why if give it the static requirement, it accepts non static vars?
Denis Lisov
@tanriol
May 08 2017 15:48
Well, it looks to me like a side effect of the rustc implementation... I don't know its internals well, but can make some guesses.
Denis Lisov
@tanriol
May 08 2017 15:55
Here's my mental model for these examples... it may be incorrect, but at least it predicts the results correctly. First, the impl Bar for Foo implements Bar not for the trait Foo (is it possible at all?), but for a typeFoo (which is unsized and can exist only as a trait object behind a fat pointer). The call will compile if some step coerces &A to &Foo.
This conversion does not happen automatically. You can call a.hello_foo() because there's no conversion - Foo is implemented for A. However, Bar is not implemented for A, only for Foo, so you need to do this cast explicitly.
In the second example, you pass a through a method call, and method call arguments are coerced to the argument type automatically.
Denis Lisov
@tanriol
May 08 2017 16:14
So &a gets coerced to &(Foo + 'some_lifetime), which is enough to call a method defined in the trait Foo. However, Bar is implemented for Foo + 'static, so this is not enough. You'd need to either coerce to&(Foo + 'static) instead (KO example), which will be enough, or implement for Foo + 'some_lifetime instead.
Sathya Narrayanan
@sourcepirate
May 08 2017 17:07
@tanriol thanks for explaining
Serhii Plyhun
@snuk182
May 08 2017 17:11
it makes sense. I would find it a use if I knew it is legal (like hidden functionality)
Zachary Golba
@zacharygolba
May 08 2017 18:01
Hi everyone! I'm wondering how you can curry more than 2 functions that take a string as an input. The following example works with i32's but not String or &str.
fn print_three(x: i32) -> Box<Fn(i32) -> Box<Fn(i32) -> ()>> {
    Box::new(move |y| Box::new(move |z| {
        println!("{}, {}, {}", x, y, z);
    }))
}

fn main() {
    print_three(1)(2)(3);
}
&'static str also works so I guess this is about lifetimes?
Frank McSherry
@frankmcsherry
May 08 2017 18:02
fn print_three(x: String) -> Box<FnOnce(String) -> Box<FnOnce(String) -> ()>> {
Box::new(move |y| Box::new(move |z| {
println!("{}, {}, {}", x, y, z);
}))
}
Sigh.
fn print_three(x: String) -> Box<FnOnce(String) -> Box<FnOnce(String) -> ()>> {
Box::new(move |y| Box::new(move |z| {
println!("{}, {}, {}", x, y, z);
}))
}
Ok, I give up. Gitter formatting is ... =/
The issue is that you are using Fn, which is a function that can be called as many times as the caller likes. This means it cannot consume anything from its environment. Moving any of the Strings into the contained closures is consuming them.
If you use FnOnce instead, you can write this with String but the result is a function you can call once.
Zachary Golba
@zacharygolba
May 08 2017 18:05
ah good to know! thanks @frankmcsherry
(gitter formatting is rough)
Frank McSherry
@frankmcsherry
May 08 2017 18:06
I guess the question is: if someone calls your returned function with many different ys, how many copies of x do you want floating around?
You should be able to clone x and move the clone in, or wrap it in a Rc, clone that and move it in.
But you'll need to explain to Rust why it is ok that there is this x thing that you repeatedly want to move from the outer closure into the inner closure.
fn print_three(x: String) -> Box<Fn(String) -> Box<Fn(String) -> ()>> {
    Box::new(move |y| Box::new(|z| {
        println!("{}, {}, {}", x, y, z);
    }))
}
Hah! Victory.
Except, that was just the code I had in my buffer, not code that does anything useful. >.<
Frank McSherry
@frankmcsherry
May 08 2017 18:12
Here is a version that clones the string each time you invoke the resulting currying:
fn print_three(x: String) -> Box<Fn(String) -> Box<Fn(String) -> ()>> {
    Box::new(move |y| {
        let x = x.clone();
        Box::new(move |z| {
            println!("{}, {}, {}", x, y, z);
        })
    })
}
And a version that wraps x with reference counting to keep just one allocation:
fn print_three(x: String) -> Box<Fn(String) -> Box<Fn(String) -> ()>> {
    let rc = ::std::rc::Rc::new(x);
    Box::new(move |y| {
        let x = rc.clone();
        Box::new(move |z| {
            println!("{}, {}, {}", *x, y, z);
        })
    })
}
Zachary Golba
@zacharygolba
May 08 2017 18:21
wow this is awesome thank you :)
Frank McSherry
@frankmcsherry
May 08 2017 18:21
No worries. It was actually kinda interesting to work through and make sure Rust did all the right things. :)