RUST Discussion



  • EDIT: While I still have write access to the OP, this is now the Rust Coding Help thread. Please post teh codez solutions to any of my Rust development scenarios homework below.
    Or feel free to ask questions about Rust and one of our resident experts will get back to you.


    I tried to write a quick & dirty implementation of a Tree in Rust. I would imagine it's fairly entertaining to anyone who actually knows what they're doing:

    #![feature(box_syntax)]
    
    
    use TreeNode::{Node, Nil};
    
    
    enum TreeNode {
        Node(i32, Box<TreeNode>, Box<TreeNode>),
        Nil
    }
    
    
    struct Tree {
        data: i32,
        left: Option<Box<Tree>>,
        right: Option<Box<Tree>>,
    }
    
    
    impl Tree {
    
        fn new_help(v: Box<TreeNode>) -> Option<Box<Tree>> {
            if let Node(_, _, _) = *v {
                Some( box Tree::new(v) )
            } else {
                None
            }
        }
    
        pub fn new(v: Box<TreeNode>) -> Tree {
            let q = *v; //weird...
            match q {
                Node(n, l, r) =>
                    Tree { data: n,
                        left: Tree::new_help(l),
                        right: Tree::new_help(r) },
                Nil =>
                    Tree { data: 0, left: None, right: None },
            }
        }
    
    
        pub fn visit(&self, f: fn(i32) -> ()) {
    
            if let Some(ref n) = self.left {
                n.visit(f)
            }
    
            f(self.data);
    
            if let Some(ref n) = self.right {
                n.visit(f)
            }
        }
    
    }
    
    
    macro_rules! node {
        ($v:expr) => (
            box Node($v, box Nil, box Nil)
        );
        ($v:expr; (); $r:expr) => (
            box Node($v, box Nil, $r)
        );
        ($v:expr; $l:expr; ()) => (
            box Node($v, $l, box Nil)
        );
        ($v:expr; $l:expr; $r:expr) => (
            box Node($v, $l, $r)
        );
    }
    
    
    fn main() {
    
        let t0 = Tree::new(
            box Node(100,
                box Node(50,
                    box Node(0,
                        box Nil,
                        box Nil),
                    box Nil),
                box Node(150,
                    box Nil,
                    box Node(200,
                        box Nil,
                        box Nil))
            )
        );
    
        let t1 = Tree::new(
            node!(100;
                node!(50;
                    node!(0);
                    ());
                node!(150;
                    ();
                    node!(200))) );
    
        fn p(x: i32) { println!("... {}", x) }
        let l = |&:x: i32| { println!("... {}", x) };
    
        t0.visit(p);
        t1.visit(p);
    
    //    t0.visit(l); // doesn't work?
    //    t1.visit(l); // doesn't work?
    
        println!("ok");
    }
    

    Code was updated to use if let syntax...)

    There's a function called Tree::new() which builds trees (calling into new_help() from time to time). Once you've built a tree you can call visit() on it and visit each node in the order they were created. Sorting (or in fact, anything useful at all) is not supported. Release early, release often!

    If I wanted to go to town on it, I'd probably spend a bit more time working on the node! macro to make building literal trees a bit less syntax heavy. Having to call Tree::new() and then use a special macro inside it is pretty dumb, but whatever. It's mildly less annoying than Tree::new(box Node(100, box Node(50, box Nil, box Nil), box Nil, box, box, box, box, pox, box, eggs and spam).

    Actually that maybe a sign that I'm probably doing too much boxing and unboxing, and there's some reference-stealing shenanigans which I managed to hide by copying an object (I think) with let q = *v; //weird.

    Also I couldn't get closures to work properly for some reason, and all the online docs seem to be referring to a version of Rust that no longer exists, and that didn't help much either...



  • // Go's concurrency primitives make it easy to
    // express concurrent concepts, such as
    // this binary tree comparison.
    //
    // Trees may be of different shapes,
    // but have the same contents. For example:
    //
    //        4               6
    //      2   6          4     7
    //     1 3 5 7       2   5
    //                  1 3
    //
    // This program compares a pair of trees by
    // walking each in its own goroutine,
    // sending their contents through a channel
    // to a third goroutine that compares them.
    
    package main
    
    import (
    	"fmt"
    	"math/rand"
    )
    
    // A Tree is a binary tree with integer values.
    type Tree struct {
    	Left  *Tree
    	Value int
    	Right *Tree
    }
    
    // Walk traverses a tree depth-first,
    // sending each Value on a channel.
    func Walk(t *Tree, ch chan int) {
    	if t == nil {
    		return
    	}
    	Walk(t.Left, ch)
    	ch <- t.Value
    	Walk(t.Right, ch)
    }
    
    // Walker launches Walk in a new goroutine,
    // and returns a read-only channel of values.
    func Walker(t *Tree) <-chan int {
    	ch := make(chan int)
    	go func() {
    		Walk(t, ch)
    		close(ch)
    	}()
    	return ch
    }
    
    // Compare reads values from two Walkers
    // that run simultaneously, and returns true
    // if t1 and t2 have the same contents.
    func Compare(t1, t2 *Tree) bool {
    	c1, c2 := Walker(t1), Walker(t2)
    	for {
    		v1, ok1 := <-c1
    		v2, ok2 := <-c2
    		if !ok1 || !ok2 {
    			return ok1 == ok2
    		}
    		if v1 != v2 {
    			break
    		}
    	}
    	return false
    }
    
    // New returns a new, random binary tree
    // holding the values 1k, 2k, ..., nk.
    func New(n, k int) *Tree {
    	var t *Tree
    	for _, v := range rand.Perm(n) {
    		t = insert(t, (1+v)*k)
    	}
    	return t
    }
    
    func insert(t *Tree, v int) *Tree {
    	if t == nil {
    		return &Tree{nil, v, nil}
    	}
    	if v < t.Value {
    		t.Left = insert(t.Left, v)
    		return t
    	}
    	t.Right = insert(t.Right, v)
    	return t
    }
    
    func main() {
    	t1 := New(100, 1)
    	fmt.Println(Compare(t1, New(100, 1)), "Same Contents")
    	fmt.Println(Compare(t1, New(99, 1)), "Differing Sizes")
    	fmt.Println(Compare(t1, New(100, 2)), "Differing Values")
    	fmt.Println(Compare(t1, New(101, 2)), "Dissimilar")
    }
    


  • @ben_lubar said:

    ```
    func Walker(t *Tree)

    <img src="/uploads/default/14457/a8869dcb59fef070.jpg" width="250" height="139">

  • Discourse touched me in a no-no place



  • That's some ugly ass syntax you've got there Rust.

    Nil => None,
    

    I don't even...



  • @Eldelshell said:

    ```
    Nil => None,

    
    That's probably my fault, not Rust's.
    
    `Option<T>` has two constructors: `Some(T)` and `None`. (It's basically the same thing as Haskell's `Maybe`).
    
    My `TreeNode` enum also has two constructors: `Node(i32, Box<TreeNode>, Box<TreeNode>)` for the case where the node is present, and `Nil` for the case where it isn't. That code says that if the `TreeNode` data contains a `Nil`, we should populate the corresponding `Tree` with a `None`...


  • @Eldelshell said:

    That's some ugly ass syntax

    This is probably the 20 years of accumulated aesthetic damage talking, but I don't think the Rust code looks any worse than equivalent C++ would...



  • Reposting my comment from http://what.thedailywtf.com/t/global-state-for-20-ill-do-things-george-lucas-could-never-dream-of-br-hr-filed-under-freejarjar-com/1673/9448 (Not quoting it because that would just f___ it up...)

    Status: Trying to convert this Javascript function into a Rust equivalent. (Should be easy enough, right?)

    function closure(start) {
        var v = start;
        return function(a) {
            console.log(v + " + " + a + " = " + (+v + a));
            v += a;
            return v;
        }
    }
    
    

    Wishing that "explicit lifetime bounds" were documented in a comprehensible manner anywhere on the whole of the internet:

    closure.rs:3:32: 3:45 help: this function's return type contains a borrowed value, but the signature does not say which one of `start`'s 0 elided lifetimes it is borrowed from
    closure.rs:3 fn make_closure(start: i32) -> &Fn<i32, i32> {
                                                ^~~~~~~~~~~~~
    closure.rs:3:33: 3:45 error: explicit lifetime bound required
    closure.rs:3 fn make_closure(start: i32) -> &Fn<i32, i32> {
                                                 ^~~~~~~~~~~~
    

    EDIT: This the the entirety of Rust's closure reference docs? TINLEYR

    And edited to fix the formatting because of fucking course the formatting was broken...



  • OK, so I got as far as this and I'm bored now:

    #![feature(box_syntax)]
    
    fn make_closure<'a>(start: i32) -> Box<Fn(i32) -> i32 + 'a> {
    
        let mut v = box start;
    
        box move |&:a: i32| -> i32 {
            let t = *v + a;
            println!("{} + {} = {}", *v, a, t);
    //        *v = t; // cant write to the local 'mut v' TDEMSYR
            t
        }
    }
    

    Note that it doesn't accumulate the values passed into the closure like the JS one does (v += a), because Rust won't let me have a mutable reference to the value v even though it is plainly delared as mutable.

    It took me hours to get this far with it, and this is the worst documented programming language ever. There are just entire swathes of the language syntax and concepts which aren't even touched on in the reference. It's abysmal. This whole <'a> business is supposed to indicate the "lifetime" of the closure and/or the variable v within the closure, so the compiler can verify that the memory is being used safely, but I have no f___ing idea how to indicate that correctly because there are no valid examples to be found anywhere. What the hell is a Box<Fn(i32) -> i32 + 'a> and how am I supposed to be able to reason about it without docs? Half of the existing writings online about Rust are referring to a pre-alpha version with completely different syntax. How very useful.

    It shouldn't take me 2½ hours to (fail to) write an embarrassingly basic function which returns such a simple a closure in any language. The JS one took 5 minutes, by comparison. Even a in C++ version of it could be done in 10mins, and the C++ version would probably have had to fake closures because it didn't even have proper lambda functions until about 25 minutes ago.

    I was all excited about knocking up a little web application or something in Rust yesterday, but now I'm not even sure there's any point continuing with this at all until there is documentation of the core language to the point you can actually get something done with it... Fuck.


  • Discourse touched me in a no-no place

    I'm sorry, but the people who need to get your message — initially about the lack of documentation I suppose — aren't reading this thread. Sounding off on the internet is easy, but it helps a lot if you rant where someone who will be able to help (i.e., not me ;)) will notice.



  • I was just thinking how similar Rust's syntax is to Go.


    They both throw away the simple OO benefit of having an entire class at the same indentation level.


  • Banned

    @tar said:

    enum TreeNode {
    Node(i32, Box<TreeNode>, Box<TreeNode>),
    Nil
    }

    I wanted to say type TreeNode = Option<(i32, Box<TreeNode>, Box<TreeNode>> but apparently this is illegal. Weird, considering that it works just fine with enum declaration. Still, I would make struct TreeNode and use Option<TreeNode>, not a self-made enum that's essentialy Option.

    @tar said:

    match *v {
    Node(_, _, _) => Some( box Tree::new(v) ),
    Nil => None,
    }

    if let Node(_, _, _) = *v {
        Some(box Tree::new(v))
    } else {
        None
    }
    

    @tar said:

    match self.left {
    Some(ref n) => n.visit(f),
    None => ()
    }

    Again, if let. Without else this time.

    @tar said:

    Also I couldn't get closures to work properly for some reason, and all the online docs seem to be referring to a version of Rust that no longer exists, and that didn't help much either...

    Closures are simple - as an argument, you take either of Fn, FnMut or FnOnce traits depending on what you need (Fn if you need immutability of function's environment, e.g. for ordering functions; FnMut if you need multiple calls; FnOnce otherwise). You declare closure like "|a| a+1" - between || are the arguments, and after that is expression. Local variable binding is done automatically. Sometimes you get "cannot infer type of closure" error - usually when storing a closure in a variable, as opposed to declaring as argument to some function - in this case, you declare the closure as |&: a|, |&mut: a| or |: a|, which correspond to Fn, FnMut and FnOnce respectively.



  • @dkf said:

    I'm sorry, but the people who need to get your message — initially about the lack of documentation I suppose — aren't reading this thread. Sounding off on the internet is easy, but it helps a lot if you rant where someone who will be able to help (i.e., not me ) will notice.

    If the people designing Rust don't already have this message, then it's a hopeless cause. It'll just go down in the sinking mire of open source languages with zero documentation and zero useful tools along with all the others.

    And yes I get that it's been alpha for all this time, but if they aren't updating the documentation simultaneously with updating the language, they are bad software developers and Rust is going to turn out to be nothing but a disappointing ball of shit.



  • @Gaska said:

    Closures are simple

    Ah, good!

    @Gaska said:

    as an argument, you take either of Fn, FnMut or FnOnce traits depending on what you need (Fn if you need immutability of function's environment, e.g. for ordering functions; FnMut if you need multiple calls; FnOnce otherwise). You declare closure like "|a| a+1" - between || are the arguments, and after that is expression. Local variable binding is done automatically. Sometimes you get "cannot infer type of closure" error - usually when storing a closure in a variable, as opposed to declaring as argument to some function - in this case, you declare the closure as |&: a|, |&mut: a| or |: a|, which correspond to Fn, FnMut and FnOnce respectively.

    ...

    ...

    SIMPLE!

    No, look buddy. That ain't simple. Simple is Lincoln Logs. That's a long paragraph full of unexplained abbreviations, strange syntax, and rarely-encountered jargon.


  • Banned

    @blakeyrat said:

    That's a long paragraph

    It's not that easy to stuff syntax and semantics of three different language constructs and the associated three function types in a short paragraph, is it?

    @blakeyrat said:

    full of unexplained abbreviations

    I explained all three I used, which aren't even abbreviations but actual names for things. "int" isn't abbreviation, it's a type. So are Fn, FnMut and FnOnce.

    @blakeyrat said:

    strange syntax

    All syntax is strange if you see it the first time.

    @blakeyrat said:

    rarely-encountered jargon

    Argument, trait, immutability, function's environment, ordering, closure, expression, local variable, binding. Which of these are rarely encountered?


  • Banned

    BTW. When I first seen C#'s "a => a+1" syntax for the first time, I was just as "WTF is that" as you are. But I was 16 back then.



  • @Gaska said:

    It's not that easy to stuff syntax and semantics of three different language constructs and the associated three function types in a short paragraph, is it?

    Right; **then why did you use the word 'simple'?**That's what I'm objecting to.

    No; it's not simple. It's beyond probably 95% of the general population. And the 5% capable of understanding it would require hours of research. There is no way the word 'simple' applies here.

    The only reason you typed 'simple' is to give us some of that typical high priesthood of technology douchbaggery: "oh it's simple to me, I guess you are just too dumb to follow all that". But in a nicely condensed form.


  • ♿ (Parody)

    @blakeyrat said:

    Right; then why did you use the word 'simple'?

    Blech...because what's simple to one person isn't simple to another. Is that so difficult?


  • Banned

    @blakeyrat said:

    Right; then why did you use the word 'simple'?That's what I'm objecting to.

    Because it's simple to understand.

    @blakeyrat said:

    It's beyond probably 95% of the general population.

    Programming in nutshell.

    @blakeyrat said:

    And the 5% capable of understanding it would require hours of research.

    It takes you hours to read six and a half lines of text ⁉

    @blakeyrat said:

    The only reason you typed 'simple' is to give us some of that typical high priesthood of technology douchbaggery: "oh it's simple to me, I guess you are just too dumb to follow all that". But in a nicely condensed form.

    No, it's because I think the concept is simple. Because it is. It's just that documentation sucks. I went through the trouble of finding the necessary information, and I shared my knowledge here so @tar doesn't have to browse Github again.

    Edit: I'm still waiting for you to tell me which of the words I used is rarely used jargon.



  • @Gaska said:

    It takes you hours to read six and a half lines of text

    I said understand, not read.

    @Gaska said:

    No, it's because I think the concept is simple.

    Well you're wrong. Not only that, but this concept builds on about 46 other concepts, none of which are simple.

    @Gaska said:

    I went through the trouble of finding the necessary information, and I shared my knowledge here so @tar doesn't have to browse Github again.

    No; you shared it here because you can make yourself look smarter than everybody else. If it happens to help someone, that's just a side-effect.

    If you don't want people to call you out on your high priesthood bullshit, the solution is to not post it in the first place. Instead of saying, "it's simple" to a person who obviously does not understand it, maybe say something like, "oh this took me awhile the first time I encountered it, too." You know, empathy?

    Maybe Gaska is some kind of super-genius and this stuff is "simple" to him. Fine. But if he comes in here and he's all like, "on man this is so easy, you guys are dumb for even needing this explanation, goddamned you're so stupid, it's simple", how does that help anybody? That's the exact kind of bullshit that sends people (rightfully) running and screaming away from IT. That's the exact kind of bullshit that gives IT the monoculture of superiority complex jerks it's currently full of.

    So yes, I call out this shit when I see it.

    Understanding that paragraph is not simple, it's difficult. There's nothing wrong with not having an instinctual knowledge of those concepts. There's nothing wrong with asking questions about it. That's the attitude people should have.

    I do nothing but write code for a living, and this shit is way beyond me. (Although the whole exercise seems to me to be "make the programmer's life fucking difficult to give the compiler an easier time". Which is also the exact opposite of what I want from a computer language.)


  • Java Dev

    You cannot return a closure that refers to local variables like that. The mut v is stored on the stack, and its lifetime is only until the function returns. You have to store v somewhere else, probably in an object along with the function.


  • Banned

    @blakeyrat said:

    I said understand, not read.

    If you have no foreknowledge of Rust traits and borrowing system, I can imagine it. But my post was for those who know Rust basics. If you know the difference between & and &mut, you'll instantly understand difference between Fn and FnMut.

    @blakeyrat said:

    No; you shared it here because you can make yourself look smarter than everybody else.

    You definitely made me look smarter than yourself.

    @blakeyrat said:

    If you don't want people to call you out on your high priesthood bullshit, the solution is to not post it in the first place. Instead of saying, "it's simple" to a person who obviously does not understand it

    From what I see, @tar understands the basic idea; he just doesn't know about different types of closure.

    @blakeyrat said:

    maybe say something like, "oh this took me awhile the first time I encountered it, too."

    Except it didn't. When I finally dug out all these RFCs and blog posts (which indeed took hours, yes), I got the whole concept instantly. Not because I'm super-genius - but because it IS simple.

    @blakeyrat said:

    he's all like, "on man this is so easy, you guys are dumb for even needing this explanation, goddamned you're so stupid, it's simple"

    I'd like to ask you to turn on your laser pointer and show me where I called anyone dumb or stupid. Except for the beginning of this post, where I indirectly called you stupid, but not because you couldn't understand Rust closures. You would definitely exploit this loophole in your reply - that's why I had to call you stupid a second time just now. </GLaDOS>

    @blakeyrat said:

    Understanding that paragraph is not simple, it's difficult. There's nothing wrong with not having an instinctual knowledge of those concepts. There's nothing wrong with asking questions about it. That's the attitude people should have.

    But if the person I'm replying to shows he knows Rust basics, what's wrong with writing a post with an assumption the potential reader knows Rust basics?

    @blakeyrat said:

    I do nothing but write code for a living, and this shit is way beyond me.

    Maybe you don't know Rust? Which would be perfectly okay. I don't know Java myself, or PHP, or JavaScript, or Haskell. If one of these languages pops up in a discussion, it's natural some stuff beyond my comprehension will be mentioned. I wouldn't want every post regarding C++ destructors to have a complete explanation of exception handling system in it.


  • Banned

    I just realized I missed one blakeyrant post here.

    @blakeyrat said:

    If the people designing Rust don't already have this message, then it's a hopeless cause.

    They have. It's on their pre-1.0-todo-list.

    @blakeyrat said:

    It'll just go down in the sinking mire of open source languages with zero documentation and zero useful tools along with all the others.

    Only a Sith deals in absolutes.

    @blakeyrat said:

    And yes I get that it's been alpha for all this time, but if they aren't updating the documentation simultaneously with updating the language, they are bad software developers and Rust is going to turn out to be nothing but a disappointing ball of shit.

    The docs are mostly up to date with latest build and of moderately high quality. The closures thing is one of few things that they drastically changed and no one bothered to make easily findable, definite guide to how it works. An exception, not the rule. Although it's a pretty major fuckup on their part.


  • Banned

    @PleegWat said:

    You cannot return a closure that refers to local variables like that. The mut v is stored on the stack, and its lifetime is only until the function returns. You have to store v somewhere else, probably in an object along with the function.

    Actually, he can. That's what move is for.



  • @Gaska said:

    Closures are simple - as an argument, you take either of Fn, FnMut or FnOnce traits depending on what you need (Fn if you need immutability of function's environment, e.g. for ordering functions; FnMut if you need multiple calls; FnOnce otherwise). You declare closure like "|a| a+1" - between || are the arguments, and after that is expression. Local variable binding is done automatically. Sometimes you get "cannot infer type of closure" error - usually when storing a closure in a variable, as opposed to declaring as argument to some function - in this case, you declare the closure as |&: a|, |&mut: a| or |: a|, which correspond to Fn, FnMut and FnOnce respectively.

    I can (just about) wrap my head around what closures are. The specific problem I was running into is the object lifetime notation syntax. Trying to write an equivalant to the JS closure in post #8, I think I'm supposed to indicate that the closure I'm returning has its own lifetime, and because that's its own closure, the result from calling that would have its own lifetime too.

    Rust needs this lifetime notation so it can do its memory-safety analysis and prove there's nothing untoward going on in my code But I can't find a decent enough primer to even get started on what the lifetime notation is supposed to look like: I tried stuff like 'a Box<Fn(i31)->i32> or Box<Fn(i31)->i32>: 'a, but I think these are from Rust 0.99 or something (there's still loads of web pages about ~ clogging up my Google search, and ~ isn't a valid syntax any more. In fact, that whole syntax of Box<Fn(i32) -> i32 + 'a> is something I hacked together from a couple of SO example codes and I have no idea what it's supposed to mean or why it's syntactically valid. I suppose I could rewrite the code to use fn instead of closures, but that feels like an admission of defeat at this point (why do a fn and a closure with the same return type and arguments have different incompatible type signatures anyway?)

    I'm also suspicious as why I can't do *v = t; when v is defined as let mut v = box start. Why does the Rust compiler say my mutable reference is immutable?!

    If you can actually fix my closure example, or provide a non-broken one, that would be tremendously instructive. I think I did find a page or two with some tantalizing hints on how lifetimes should work, but I can't find them now...



  • @PleegWat said:

    You cannot return a closure that refers to local variables like that. The mut v is stored on the stack, and its lifetime is only until the function returns. You have to store v somewhere else, probably in an object along with the function.

    That makes sense, and it's probably in-line with what you'd expect from 'oldschool' C++. Let's say the exercise is to see how much 'magic' the Rust compiler will insert for your, and the answer is "not much, you need to do it yourself..."

    I guess I could look at using Gc<i32> or something to hold my v instead of a Box, maybe that'd fix it? (Although, hang on, isn't box roughly equivalent to malloc()? So what the merry hell is my Box doing on the stack in the first place?!)



  • @Gaska said:

    Actually, he can. That's what move is for.

    Interesting... I've pretty much exhausted http://rustbyexample.com, BTW.

    Is there any other α1.00-relevant documentations out there I should be reading?


  • Java Dev

    Yeah, I think I missed the box. At which point I'm not sure anymore either.

    I only read the tutorial on rust-lang, and that's a couple weeks back.


  • Banned

    @tar said:

    lifetime

    That's probably the hardest and ugliest part of Rust. I don't fully get it myself.

    Anyway, the commented line in your code works if you replace "-> Box<Fn(" with "-> Box<FnMut(". Also, I just learned that they completely abandoned explicit closure type syntax in some recent nightly.





  • I think I may step down from the brink of "closure-ception" for my next exercise though, maybe come back to it in a couple of months when some of the following hold:

    1. the language closure/lifetime syntax/semantics has stabilized.
    2. My understanding is clearer.
    3. Someone's written some nice docs.
    4. I actually have a use case for needing a closure that returns another closure.

    Filed under: it's a silly Javascript/Scheme trick anyway...



  • Coming up next, a Towers of Hanoi simulator. I mean, this is an actual implementation (although it dates from a time when move wasn't a Rust keyword, but I 'fixed' that...):

    fn move_(n: i32, from: i32, to: i32, via: i32) {
      if n > 0 {
        move_(n - 1, from, via, to);
        println!("Move disk from pole {} to pole {}", from, to);
        move_(n - 1, via, to, from);
      }
    }
     
    fn main() {
      move_(4, 1,2,3);
    }
    

    But I want to make one which draws the state of the towers after each move (in ASCII art). My current solution is probably about 40%-50% complete....



  • Da fuq is that enum? Did they just take the traditional meaning of enum used in all other languages and fucking make it different?

    Edit: O god they did. This is a "safe" language????



  • @Gaska said:

    if let ...

    Thanks, I've updated the OP to use this syntax instead of the matches. Does make the code slightly shorter (and loses the Nil => None stuff which was upsetting @Eldelshell...)

    It would probably never have occurred to me to try and put a let in the test expression of an if statement, although now I think about it, it's not a million miles away from this in C++:

    if(SomeData *data = abc->def()) {
        data->xyz()
    }


  • enum seems to mean "tagged union" in Rust. It's a thing. Personally I find the use of self instead of this to be much more upsetting.

    @delfinom said:

    This is a "safe" language????

    Seems to be 'memory safe', although that translates into 'annoying' as you need to keep the compiler informed about the lifetimes of references you want to pass from one function to another...



  • @Gaska said:

    But my post was for those who know Rust basics. If you know the difference between & and &mut, you'll instantly understand difference between Fn and FnMut.

    Ok, I couldn't find a specific point to reply this to, but @Gaska, you need to understand that you were talking to someone who had just said

    @tar said:

    I was all excited about knocking up a little web application or something in Rust yesterday, but now I'm not even sure there's any point continuing with this at all until there is documentation of the core language to the point you can actually get something done with it... Fuck.

    So, typing out a quick paragraph of your distilled understanding of closures gained from

    @Gaska said:

    RFCs and blog posts (which indeed took hours, yes)

    was probably a less useful way of convincing them that rust isn't unusable than linking to the actual RFCs and blog posts would have been. Show us where to fish, don't just give us some smelly old fish that not even @Mikael_Svahnberg could love.



  • @Buddy said:

    Show us where to fish, don't just give us some smelly old fish

    That's probably 90% of it...



  • @tar said:

    enum seems to mean "tagged union" in Rust.

    Sure, let's take a word that has been defined and then give it a different definition that isn't related at all and assume people know what we are talking about.



  • @ben_lubar said:

    Sure, let's take a word that has been defined and then give it a different definition that isn't related at all and assume people know what we are talking about.

    Oh, you mean like how C# took class and struct and decided they were just perfect for expressing refeence semantics vs value semantics, and there was no pre-existing use of the terms from which confusion could arise?

    Or how the term "goroutine" has been totally co-opted to the point where hardly anyone remembers what it used to mean?



  • @tar said:

    Or how the term "goroutine" has been totally co-opted to the point where hardly anyone remembers what it used to mean?

    A goroutine is a coroutine in the Go language.



  • @ben_lubar said:

    A goroutine is a coroutine in the Go language.

    A whoosh is a joke in the someone-didn't-get-one language.



  • I wasn't that worried about Rust at that point—I was mostly just jumping on gąska for doing the standard tdwtf thing of ignoring good advice just because of who it was coming from.

    About your Rust problems: I'm still in the process of reading thru rustbyexample, but I what I'm seeing is that Rust is militant about RA2: no variable can be created without knowing exactly when it will be destroyed (the box allocates space on the heap, but that space is freed as soon as the box goes out of scope; closing over the variable extends its scope to equal the life of the closure). So the deal with returning variablesreferences from functions is that the lifetime needs to be bound to something: the easiest way to do that is to pass a single reference in to the function, in which case the compiler will give its return value the same lifetime as the input had. And then, in the process of explicitly adding a lifetime parameter to your return value, you gave it the type Fn, which meant that the compiler could no longer infer it to be of type FnMut, which is what it would have needed to be so that it could change a mutable variable. It seems like the easiest way to make your code work would be to remove all the type annotations and figure out what type of object you need to pass in to allow it to infer the correct types.

    Edit: variable -> reference, a crucial distinction.



  • Someone's gonna have to explain the joke because it's not in the Discopaedia and I've never heard of goroutines being confusing before.



  • (post withdrawn by author, will be automatically deleted in 24 hours unless flagged)



  • I can't find any reference to a non-Go goroutine.

    Still all the results are about the language Go.



  • This post is deleted!


  • Your "joke" is that you lied to me? What?



  • Anyway, I'm making reasonable progress on the Towers of Hanoi:

    
    C:\Users\devel\scratch\rust>hanoi3.exe
    
      01    ||    ||
      02    ||    ||
      03    ||    ||
      04    ||    ||
      05    ||    ||
    _/||\__/||\__/||\_
    
    
      ||    ||    ||
      02    ||    ||
      03    ||    ||
      04    ||    ||
      05    01    ||
    _/||\__/||\__/||\_
    
    
      ||    ||    ||
      ||    ||    ||
      03    ||    ||
      04    ||    ||
      05    01    02
    _/||\__/||\__/||\_
    
    ERR: tried to push size 3 onto pole 1.
    
      ||    ||    ||
      ||    ||    ||
      03    ||    ||
      04    ||    ||
      05    01    02
    _/||\__/||\__/||\_
    
    
      ||    ||    ||
      ||    ||    ||
      03    ||    ||
      04    ||    01
      05    ||    02
    _/||\__/||\__/||\_
    
    
      ||    ||    ||
      ||    ||    ||
      ||    ||    ||
      04    ||    01
      05    03    02
    _/||\__/||\__/||\_
    
    
    C:\Users\devel\scratch\rust>
    




  • This post is deleted!

Log in to reply