These are chat archives for rust-lang/rust

20th
Apr 2017
VJ
@00imvj00
Apr 20 2017 10:18
use std::mem;

#[derive(Debug)]
enum Stack {
    Nil,
    Element {
        value: i32,
        next: Box<Stack>,
    },
}

impl Stack {

   fn new() -> Stack {
         Stack::Nil
   }

   fn push(self, val: i32) -> Stack {
            Stack::Element{value: val, next: Box::new(self)}
   }
   // fn pop(&mut self) -> i32 {

   // }
}

fn main() {

    let mut stack = Stack::new();
    println!("{:?}", mem::size_of_val(&stack));
    stack = stack.push(10);
    println!("{:?}", mem::size_of_val(&stack));
    stack = stack.push(20);
    println!("{:?}", mem::size_of_val(&stack));
    stack = stack.push(30);
    println!("{:?}", mem::size_of_val(&stack));
    stack = stack.push(40);
    println!("{:?}", mem::size_of_val(&stack));

    for i in 0..1000000 {
        stack = stack.push(i);
        if i == 9999 {
            println!("9999 reached.");
        }
    }

}
throwing stack overflow error.
thread 'main' has overflowed its stack
fatal runtime error: stack overflow
i checked the size of stack, it always remains 16 bytes as it is address to that stack first element.
what i am doing wrong here ?
Aleksey Kladov
@matklad
Apr 20 2017 10:42
@i-m-v-j SO happens when you drop stack.
The drop will recursively delete the elements of the linked list and overflow.
Sherzod Mutalov
@shmutalov
Apr 20 2017 10:49
@matklad Does it mean that rust cannot drop? o_O
Andrey Lesnikov
@ozkriff
Apr 20 2017 10:51
It just means that drop shouldn't be so deeply recursive
Diggory Blake
@Diggsey
Apr 20 2017 10:51
@shmutalov you could implement Drop for your Stack type, and implement a non-recursive algorithm to decompose the list
Sherzod Mutalov
@shmutalov
Apr 20 2017 10:52
@Diggsey SO on dropping simple objects is very unexpected :) C# can do that I guess
Diggory Blake
@Diggsey
Apr 20 2017 10:53
almost any language will do this (C++ included)
the only way to avoid it is to guarantee tail-call optimization for the drop implementation
Diggory Blake
@Diggsey
Apr 20 2017 10:56
also, you might want to define your type like this:
struct Element {
    value: i32,
    next: Option<Box<Element>>
}
type Stack = Option<Box<Element>>
that way you don't need to box your "nil" values
and you get the null-pointer optimization
VJ
@00imvj00
Apr 20 2017 11:42
so does it mean that for all kinda recursive functionality i need to implement my own drop ?? @ozkriff @Diggsey
Andrey Lesnikov
@ozkriff
Apr 20 2017 11:44
for deep recursions only - your code works fine (on playpen) with 100000 nodes
Aleksey Kladov
@matklad
Apr 20 2017 11:45
If you are writing a recursive list-like linear data structure, then you'll need to protect against recursive drop, yes. If you are writing a balanced tree, you know that it would be shallow, so you don't need this.
And if you do write something linked-list like, it may be the case that a Vec based data structure would be a better fit for the job.
VJ
@00imvj00
Apr 20 2017 11:47
it is going to be fixed in next versions ? or it is how it is in rust ? just asking , then i might have to learn how to drop. if you guys have any good articles on drop functionality then please share link with me, i would like to read it to understand how it works.
Sherzod Mutalov
@shmutalov
Apr 20 2017 11:47
@i-m-v-j ^
VJ
@00imvj00
Apr 20 2017 11:48
thank you @shmutalov
VJ
@00imvj00
Apr 20 2017 12:13
So what is the logic behind recursive drop ?? Can anyone explain ?
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:15
@i-m-v-j: I really recommend you read that link. It explains it.
Oh, that one is far into the book. This one is probably better. http://cglab.ca/~abeinges/blah/too-many-lists/book/first-drop.html
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:22
I am not rust developer, but I guess it works like following pseudo-code:
func drop(struct) {
  if isscalar(struct) {
    freemem(struct);
    return;
  }

  foreach property in struct {
    if property == null {
      continue;
    }

    drop(property);
  }
}
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:24
@shmutalov Not exactly. The basic idea is correct, but there are some important differences. First, most of the properties are inline, so you only care if they implement drop ‒ most things don't and just get freed together with the struct itself, without any additional code.
And there's no thing as null in rust.
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:27
@vorner I know about null in rust. I wrote that is pseudo-code, not actual rust core code snippet :D
VJ
@00imvj00
Apr 20 2017 12:27
Still not able to get it. Why we need it. Basic logic if someone will explain ??
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:27
Yes, as I said, the basic idea is correct.
@i-m-v-j: Do you know why recursion can overflow the stack, if it is too deep?
VJ
@00imvj00
Apr 20 2017 12:28
No
I know it will add stack frame into main stack
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:29
Each recursive call adds one frame.
VJ
@00imvj00
Apr 20 2017 12:29
Yes
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:29
And the size of the stack is limited. For some technical reasons.
VJ
@00imvj00
Apr 20 2017 12:30
Ok , then ??
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:30
(it can grow with languages like python, but C, C++, rust and many others have it limited)
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:30
@i-m-v-j Stack has limited size, depends on OS and language engine
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:30
So, if you add more frames than fits, what happens? That's a problem called stack overflow. You want to put one too many stack frames and it doesn't fit.
The languages differ in how they act in that situation, but it's usually some kind of very serious problem.
VJ
@00imvj00
Apr 20 2017 12:31
Ohk
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:31
So, if you have a very deep recursion, you just run out of the stack space and crash.
VJ
@00imvj00
Apr 20 2017 12:31
Ohk
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:32
And if you drop the list from the head like this:
I want to drop the head. OK, how do I do it? Well, first, I have to drop the rest of the list. Recursively.
I want to drop the head of the rest. How do I do it? Well, first I have to drop the rest of the rest. Recursively.
....
So you add another stack frame for each element in the list.
And if there are too many elements, then you just run out of the stack space.
VJ
@00imvj00
Apr 20 2017 12:33
Ohh
Getting it
Then ??
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:34
Well, then you crash, as you've seen yourself.
And the link provided explains how you can tell the compiler to do it differently.
VJ
@00imvj00
Apr 20 2017 12:35
Ha ha 😁
Ok.
Can u also plz explain logic how do I tell compiler ?? I m asking, honestly I want to know
I know I tell through drop
But logic ??
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:36
@i-m-v-j you want to implement Drop trait for your Stack struct
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:36
Have you read the link?
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:36
^ some examples here, but in c
VJ
@00imvj00
Apr 20 2017 12:36
Yes reading it
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:37
OK, when you finish and still don't get it, then I'll try to clarify. But the idea is there.
VJ
@00imvj00
Apr 20 2017 12:38
Thnks guys, will ping if it doesn't get into my stupid mind
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:40
@i-m-v-j I recommend you to not use "linked" list for your stack, try rewrite it with Vec
VJ
@00imvj00
Apr 20 2017 12:40
Hmm, I was learning to build data structures
Raw
vorner @vorner had the impression the implementation of a linked list was an exercise, not as a means to some goal.
shmutalov @shmutalov agrees with @i-m-v-j and @vorner
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:41
Though linked lists are a bit hard in rust ‒ as the book explains.
Denis Lisov
@tanriol
Apr 20 2017 12:43
Well, at least they're easier than graphs...
Michal 'vorner' Vaner
@vorner
Apr 20 2017 12:44
@tanriol It depends on what implementation of graphs. I studied applied mathematics, which is basically computer science around combinatorics and graphs. I never used any other representation than two arrays (one for edges, another for vertices) indexed by integers. And that was in C which makes abusing pointers easy.
Sherzod Mutalov
@shmutalov
Apr 20 2017 12:46
Graphs is easy too, but algorithms
d2a4u
@d2a4u
Apr 20 2017 21:19
hi, is it possible to reference to a function of an instant without calling it? I'm trying to make callback function like this but getting error: attempted to take value of method send on type client::Client<'_>.
// client.rs file
struct Client<'a> {
    base_url: &'a str,
}

impl<'a>  Client<'a> {

    pub fn new(base_url: &'a str) -> Client<'a> {
        Client {
            base_url: base_url,
        }
    }

    fn send(&self) -> Result<()> {
        let endpoint = self.base_url.to_string() + "/api";
        // send request to endpoint ...
    }
}

// main.rs file
fn doSomethingThenCallback(f: fn() -> Result<()>) -> Result<()> {
    // do stuff ...
    f()
}

fn main() {
    let url = "www.sample.com";
    let client = Client::new(url);
    let callback = client.send; // <- I would like callback to be of type fn() -> Result<()>
    doSomethingThenCallback(callback);
}
Tim
@tikue
Apr 20 2017 21:31
@d2a4u no it's not possible, you'd need to do let callback = || client.send(); I don't know if there's a technical limitation or if it simply hasn't been implemented. client::send would be ambiguous due to the module namespace but I don't know if there's any ambiguity in client.send.
d2a4u
@d2a4u
Apr 20 2017 21:36
@tikue I have tried let callback = || client.send(); as well but I get expected fn pointer, found closure from compiler, namespace isn't an issue in the real code, I just quickly did a code snippet, although client::send doesn't work as well, I get not found in 'client'
Tim
@tikue
Apr 20 2017 21:36
@d2a4u you need to change fn doSomethingThenCallback to look like this:
fn doSomethingThenCallback<F: Fn() -> Result<()>>(f: F) -> Result<()> {
    // do stuff...
    f()
}
@d2a4u regarding the namespace stuff, I was talking about possible issues with a potential extension to the rust language to support the syntax you were using (which doesn't currently exist)
d2a4u
@d2a4u
Apr 20 2017 21:42
@tikue ahh, I see, sorry I'm new to rust so got confused. But hey, your snippet works. Thank you so much, would you mind explain why generic works but mine doesn't?
Jonas Platte
@jplatte
Apr 20 2017 21:48
@d2a4u A closure that captures part of the envionment (the variable client in your case) can't be coerced to function pointer because it contains that part of the environment in addition to the function pointer.
Tim
@tikue
Apr 20 2017 21:48
@d2a4u so fn() is actually a type, it basically means a function pointer
like, fn hello() { println!("Hello World"); } has type fn()
Jonas Platte
@jplatte
Apr 20 2017 21:49
So closures (except those that don't capture anything) are fat pointers.
Tim
@tikue
Apr 20 2017 21:49
closures, like || println!("Hello World") have a type that can't be named, but they implement the Fn traits
in the future, closures without environments will be able to be coerced to fn() but that's not implemented yet
(and wouldn't help in this case, since you're capturing client)
Jonas Platte
@jplatte
Apr 20 2017 21:50
Well, it's not in stable, but it is implemented in nightly and can be enabled with #![feature(closure_to_fn_coercion)] ;)
But yeah, doesn't apply here anyway, because the callback is a fat pointer.
Might be worth noting that Fn is more or less just a normal trait. The only thing special about it is the syntax sugar for it.
I think... Should actually look that up :D
Hm, not documented in very much detail, but AFAICT Fn(A, B) -> C translates to Fn<(A, B), Output = C>
d2a4u
@d2a4u
Apr 20 2017 21:54
in that case, does fn() type extend Fn trait?
Jonas Platte
@jplatte
Apr 20 2017 21:55
Yes, all function types implement Fn.
d2a4u
@d2a4u
Apr 20 2017 21:56
I think I understand now, thanks @tikue and @jplatte . It was very helpful
Tim
@tikue
Apr 20 2017 22:19
@jplatte the only thing special is that the traits themselves are not stable yet
Jonas Platte
@jplatte
Apr 20 2017 22:19
Oh, that too? Interesting.
Tim
@tikue
Apr 20 2017 22:20
which is annoying for rolling your own struct-closure
Anirudh Vyas
@AnirudhVyas
Apr 20 2017 22:33
Hi - I have a newbie question - I am trying to cargo build my project but it seems like there is never any compilation error - i go and compile individual rs files using rustc and it starts complaining, what would be wrong? Sorry if this is not a beginners community, thought I'd just ask...can anyone point me to right direction or suggest any source for reading up?
Denis Lisov
@tanriol
Apr 20 2017 22:34
Have you mentioned the other files from your main.rs or lib.rs?
Also, note that Rust's compilation unit is a crate, not a file. It's pretty much expected that compiling one individual .rs file out of a project will fail.
Anirudh Vyas
@AnirudhVyas
Apr 20 2017 22:39
I see - when you say mentioned other files do you mean as a pattern in cargo toml? or simply cargo build src/some_rust_file.rs
Denis Lisov
@tanriol
Apr 20 2017 22:41
I mean that an example foo.rs file normally represents a foo module and is declared as mod foo; in main.rs / lib.rs / mod.rs
When you do cargo build, it starts from main.rs or lib.rs and takes for building the source file for every module declared in them (and in other modules).
Anirudh Vyas
@AnirudhVyas
Apr 20 2017 22:47
you sir are a great man ...
i realized when you said "I mean that an example foo.rs file normally represents a foo module and is declared as mod foo; in main.rs / lib.rs / mod.rs" that I was ignoring something that i should have read before
totally my fault but really a necessary read. thanks - I am getting compilation errors now
i had lib.rs missing
appreciate your help!