These are chat archives for rust-lang/rust

19th
Nov 2016
Thomas Koehler
@Bastacyclop
Nov 19 2016 10:02
Does this mean that HashMap is allocating a lot more than Vec or is capacity a bad way to get an idea of the hashmap's allocated memory ? https://is.gd/gJVVpO
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:07
@Bastacyclop yeah, it’s’ not a sensible way.
Thomas Koehler
@Bastacyclop
Nov 19 2016 10:08
@lifthrasiir is there another way ?
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:09
it’s not easy. Rust’s hash table (map and set) implementation only guarantees that you can add t.capacity() - t.len() more items without allocating, which doesn’t exactly mean that exactly t.capacity() items are allocated.
@Bastacyclop my guess is that in the current implementation you can calculate 1.1x the reported capacity to get the approximate capacity in use
you should also account that String, for example, actually use two more words for its own length and capacity
on the other hands, in your example, you are storing &’static str that does not take an additional memory. the per-item size would be (in 64-bit platforms) 24 bytes then, regardless of the string’s size.
(I believe this is just an illustrative example though)
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:14
@Bastacyclop why do you need this exact information?
Thomas Koehler
@Bastacyclop
Nov 19 2016 10:16
@lifthrasiir Thanks! Yes, I was comparing two tree implementations (on with Vecs and one with HashMaps) and wanted to get an allocated memory comparison. I was surprised by the resulting hashmap allocations.
But if hashmap.capacity() is less than the allocated memory, then it does allocate more than Vec ?
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:18
not always, because the hash map should also keep its hash value.
Thomas Koehler
@Bastacyclop
Nov 19 2016 10:21
Is there any chance to see some kind of hashmap.memory_usage() method in the future ? Even if it is not performant and only meant for debug and statistics ?
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:22
if my reading of the actual implementation is correct, the actual thing being allocated is like:
struct TrueHash<const Cap: usize, K, V> { // `const` for value generics, current does not actually exist
    hashes: [u64; Cap],
    pairs: [(K, V); Cap],
}
so what you should do for the most exact statistics is that, first estimate the raw capacity first; then calculate the size of the above struct, accounting for the alignment as well.
Jonas Platte
@jplatte
Nov 19 2016 10:23
@Bastacyclop If you want to compare actual memory usage, I think the most sensible way would be to implement an example program once for each structure you're testing, and run each through massif (one of the tools in the valgrind tool suite).
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:24
@Bastacyclop if you just want to see what happens when replacing Vec with HashMap or vice versa, how about just doing that?
Thomas Koehler
@Bastacyclop
Nov 19 2016 10:25
I will try that, thank you both :)
Kang Seonghoon
@lifthrasiir
Nov 19 2016 10:26
memory allocation is quite complex and relies on many factors, including the allocator being used (jemalloc in Rust—that’s why you don’t pay the additional cost for small allocations, it’s optimized)
so looking at the farthest sight would be better, in my opinion.
(unless you are doing libraries :p)
Pavel Meledin
@btbvoy
Nov 19 2016 16:13

Hi everyone, Could sombody describe me what makes compiler to show me such an error:

locale: self.locale
        ^^^^ cannot move out of borrowed content

I’m following this guide https://doc.rust-lang.org/book/method-syntax.html with builder section. I have the following code:

#[derive(Debug)]
pub enum LocaleCode {
    UA
}

#[derive(Debug)]
pub struct LocalizedField {
    pub locale: LocaleCode
}

pub struct LocalizedFieldBuilder {
    locale: LocaleCode
}

impl LocalizedFieldBuilder {

    pub fn new() -> LocalizedFieldBuilder {
        LocalizedFieldBuilder {
            locale: LocaleCode::UA
        }
    }

    pub fn locale(&mut self, locale_code: LocaleCode) -> &mut LocalizedFieldBuilder {
        self.locale = locale_code;
        self
    }

    pub fn build(&self) -> LocalizedField {
        LocalizedField {
            locale: self.locale // the error occures here: cannot move out of borrowed content (it highlights self with 4 symbols: ^^^^)
        }
    }
}

What is wrong here?

Elliott Linder
@darfink
Nov 19 2016 16:17
Derive copy and/or clone for LocaleCode
You are trying to move ownership of the value when you instead want to copy it.
Is it possible to assert that a function has been called when unit testing?
Pavel Meledin
@btbvoy
Nov 19 2016 16:19
eventually I do want to cover it by tests but at the moment I’m just playing with calling this code from main.rs
I’m doing it like this:
fn main()
{
    let n = LocalizedFieldBuilder::new()
        .locale(LocaleCode::UA)
        .build();

    println!("{:?}", n);
so if I got you right - that means that in buildof builder I have to copy a value in order not to have links from builder itself from produced value and once result will be returned into n the builder itself will be destroyed and n will not depend on LocaleCode since it was copied ?
did I get you right ? :-)
Pavel Meledin
@btbvoy
Nov 19 2016 16:27
well it work with fixes that you suggested @darfink :-) thanks
however I still didn’t get why examples from rust docs is working
ah probably because it uses primitive types
but enum is custom type
David McGillicuddy
@djmcgill
Nov 19 2016 18:35
Where's it typical to put all your extern crates in Rust in exe's? All in your main.rs, or just in modules as needed and let the compiler figure out duplicates?
Kang Seonghoon
@lifthrasiir
Nov 19 2016 18:36
normally at the topmost level, unless you need to put it under #[cfg]s
Arthur Silva
@arthurprs
Nov 19 2016 19:20
Let's rejoice rust-lang/rust truck factor of 9
Pavel Meledin
@btbvoy
Nov 19 2016 19:27

I have the following code:

#[derive(Debug, Clone, Copy)]
pub enum LocaleCode { UA }

#[derive(Debug)]
pub struct LocalizedFieldBuilder<'a> {
    locale: LocaleCode,
    value:  &'a str
}

impl<'a> LocalizedFieldBuilder<'a> {

    pub fn new() -> LocalizedFieldBuilder<'a> {
        LocalizedFieldBuilder {
            locale: LocaleCode::UA,
            value:  ""
        }
    }

    pub fn locale(&mut self, locale_code: LocaleCode) -> &mut LocalizedFieldBuilder<'a> {
        self.locale = locale_code;
        self
    }

    pub fn value(&mut self, value: &'a str) -> &mut LocalizedFieldBuilder<'a> {
        self.value = value;
        self
    }

    pub fn build(&self) -> LocalizedField {
        LocalizedField {
            locale: self.locale.clone(),
            value: self.value
        }
    }
}

when I do

let n = LocalizedFieldBuilder::new();
println!("{:?}", n);

then it initialize n as instance of LocalizedFieldBuilder. But if I do this:

let n = LocalizedFieldBuilder::new()
        .locale(LocaleCode::UA)
        .value("A")
        .build();

    println!("{:?}", n);

compiler says:


     let n = LocalizedFieldBuilder::new()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough

I thougt that new() should return an instance of LocalizedFieldBuilder and then using a chain of calls which I assumed should be performed on this newly created instance and then build() should produce LocalizedField instance which will be assigned to n. At which point I missed something ? :-) Please point me

Jonas Platte
@jplatte
Nov 19 2016 19:32
@btbvoy Is the line with does not live long enough the last line of the error message, or is there more context in the actual error message?
Pavel Meledin
@btbvoy
Nov 19 2016 19:33
ah you are right there is line before this meesage: error: borrowed value does not live long enough
hold on
I took into account futher suggestions of the compiler
and changed to this:
let mut builder = LocalizedFieldBuilder::new();

    let n = builder.locale(LocaleCode::UA)
        .value("A")
        .build();

    println!("{:?}", n);
now it strated working
but I still can’t get what is wrong in my previous example ?
my assumption is - lifetime but :-) lifetime of what ? :-D
Pavel Meledin
@btbvoy
Nov 19 2016 19:40
@jplatte whole output from compiler looks like this:
error: borrowed value does not live long enough
  --> src/main.rs:20:13
   |
20 |     let n = LocalizedFieldBuilder::new()
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
   |
note: reference must be valid for the block suffix following statement 0 at 23:17...
  --> src/main.rs:23:18
   |
23 |         .build();
   |                  ^
note: ...but borrowed value is only valid for the statement at 20:4
  --> src/main.rs:20:5
   |
20 |     let n = LocalizedFieldBuilder::new()
   |     ^
help: consider using a `let` binding to increase its lifetime
  --> src/main.rs:20:5
   |
20 |     let n = LocalizedFieldBuilder::new()
   |     ^

error: aborting due to previous error

error: Could not compile
Jonas Platte
@jplatte
Nov 19 2016 19:48
@btbvoy I think your problem is that the compiler won't infer that the reference returned by your builder functions (locale, value) lives exactly as long as the self reference.
Have a look at how the builder functions are defined on https://aturon.github.io/ownership/builders.html

I think you have to change

pub fn locale(&mut self, locale_code: LocaleCode) -> &mut LocalizedFieldBuilder<'a>

to

pub fn locale<'s>(&'s mut self, locale_code: LocaleCode) -> &'s mut LocalizedFieldBuilder<'a>
and the same for value
Pavel Meledin
@btbvoy
Nov 19 2016 19:50
hm interesting, trying now your suggestions
David Harvey-Macaulay
@alteous
Nov 19 2016 19:50
Hello, I need to debug a crate dependency in an executable built with cargo. Could this be done with rust-gdb? I've tried rust-gdb target/debug/my_executable with break main. The debugging symbols seem to be there but there is no source code. I can't seem to find any documentation on how to do this. Could anybody help me out?
Jonas Platte
@jplatte
Nov 19 2016 19:54
@Alteous I have a relatively simple to setup lldb+vscode debugging environment, if you'd be interested in that as an alternative I could tell you how to set it up. Although I didn't have any issues debugging with a normal gdb either (as an arch linux user, where you get gdb 7.12 from the repos)
I just tested whether external crates work with the first setup, and they do. The only thing the debugger can't find the source for is the standard library.
David Harvey-Macaulay
@alteous
Nov 19 2016 19:55
@jplatte Yes that sounds great! I'll go ahead and (re)download VS code. I'm using Fedora 24 btw.
Jonas Platte
@jplatte
Nov 19 2016 19:56
Okay, what version of lldb does Fedora 24 have?
David Harvey-Macaulay
@alteous
Nov 19 2016 19:56
lldb-3.8.0-1
Jonas Platte
@jplatte
Nov 19 2016 19:57
oh
that's problematic
David Harvey-Macaulay
@alteous
Nov 19 2016 19:57
I might be able to find another. What version do you have?
Jonas Platte
@jplatte
Nov 19 2016 19:57
I have 3.9
David Harvey-Macaulay
@alteous
Nov 19 2016 19:59
Haha typical, 3.7 and 3.9 supported but not 3.8
Pavel Meledin
@btbvoy
Nov 19 2016 20:01
@jplatte Frankly speaking I still don’t have clear understaning of lifetime feature but I added <‘s> for locale & value and tried to compile but the error stays exactly the same
Jonas Platte
@jplatte
Nov 19 2016 20:02
Well when it comes to more complex situations like this I also don't really know what I'm doing.
David Harvey-Macaulay
@alteous
Nov 19 2016 20:02
@jplatte I'll try building from source
Jonas Platte
@jplatte
Nov 19 2016 20:02
Otherwise I wouldn't have suggested something that doesn't work ^^°
Pavel Meledin
@btbvoy
Nov 19 2016 20:02
I did read pages about lifetime from official doc & rust by example but I’m still kind of blind about how it works
maybe you can suggest some other sources about this feature ?
Jonas Platte
@jplatte
Nov 19 2016 20:03
@btbvoy I'll try to reproduce your problem and see if I can figure it out
Pavel Meledin
@btbvoy
Nov 19 2016 20:03
@jplatte wow, that’s awesome :-) thanks a lot
Jonas Platte
@jplatte
Nov 19 2016 20:06
So how is LocalizedField defined? I assume something like this?
struct LocalizedField {
    locale: LocaleCode,
    value: &str,
}
And why does LocalizedField not have a lifetime argument while LocalizedFieldBuilder does?
Pavel Meledin
@btbvoy
Nov 19 2016 20:09
here is how it’s defined:

#[derive(Debug)]
pub struct LocalizedField<'a> {
    pub locale: LocaleCode,
    pub value:  &'a str
}
Jonas Platte
@jplatte
Nov 19 2016 20:10
Oh....
Huh
Pavel Meledin
@btbvoy
Nov 19 2016 20:10
might be I didn’t pass lifetime parameter further when builder creates the final structure ?
:-D
Jonas Platte
@jplatte
Nov 19 2016 20:11
I expected that you would have to supply that parameter in the build function signature
but maybe not
Pavel Meledin
@btbvoy
Nov 19 2016 20:11
will try
Jonas Platte
@jplatte
Nov 19 2016 20:11
Yeah I guess that might also be a problem
Oh yeah that fixes it
without any other changes
I guess I accidentally found your problem :D
Pavel Meledin
@btbvoy
Nov 19 2016 20:13
yeah :-) thanks a lot :-)
btw, am I getting lifetime feature as a label feature which mark some members of function / impland all everyone who marked with this certain “label” - shuold be accessible in the same period of time and scope. Is such idea close to what it is ?
Jonas Platte
@jplatte
Nov 19 2016 20:23
@btbvoy I think I've seen it explained as compile-time reference counting with a maximum count of 1... if that makes sense ^^
and yeah, named lifetimes kind of work like how you described it.
Pavel Meledin
@btbvoy
Nov 19 2016 21:13
@jplatte I see. Thanks :-)