RUST Discussion


  • Banned

    @blakeyrat said:

    Maybe I'm confusing it with some other new-fangled language, but wasn't Rust explicitly designed to not have/require "Null" (or equivalent)?

    Yes it is. But void is still needed - for example, when you want a function that doesn't return anything.

    @Yamikuronue said:

    Which is fucking hilarious because:


    It's unsafe, so it doesn't count.


  • I survived the hour long Uno hand

    @Gaska said:

    It's unsafe, so it doesn't count.



  • @Gaska said:

    Yes it is. But void is still needed - for example, when you want a function that doesn't return anything.

    C doesn't have the ability to assign void to a variable. Why is Rust worse than C?



  • @Gaska said:

    Value-y assignment exists exclusively in C

    It's not a C innovation. Algol did it first IIRC.


  • Banned

    @ben_lubar said:

    C doesn't have the ability to assign void to a variable. Why is Rust worse than C?

    Rustistency.



  • @tar said:

    We can invent a hypothetical idiot who has trouble with anything.

    Don't even need to. He's right here in this very thread.



  • There are three cases for "this function doesn't return anything":

    • This function doesn't return

      func Foo() {
          os.Exit(0)
      }
      
    • This function returns zero values

      func Bar() {
      }
      
    • This function returns a value with no data

      func Baz() (useless struct{}) {
          return
      }
      

    Does Rust not support all three?



  • @Gaska said:

    Yes it is. But void is still needed - for example, when you want a function that doesn't return anything.

    I wouldn't say it's needed. If the function returns nothing, just ... don't return anything? And don't put any types in its definition?

    The only reason it's really "needed" is so the programmer asserts he's not returning anything on purpose, so the compiler can catch that type of error. Which is useful, but not exactly Earth-shatteringly important.



  • If assignment doesn't return the value on the right hand side, it shouldn't be an expression.


  • Banned

    @ben_lubar said:

    There are three cases for "this function doesn't return anything":

    • This function doesn't return
    • This function returns zero values
    • This function returns a value with no data

    Does Rust not support all three?


    In Rust, they're all equivalent - except maybe for the last one, when you don't return just any non-value, but a non-value of a particular type that's very important.

    @blakeyrat said:

    I wouldn't say it's needed. If the function returns nothing, just ... don't return anything? And don't put any types in its definition?

    Well, syntactically, it works exactly like this. But technically, it's implicitly returning void. Also, it eases up implementation significantly - especially when everything is an expression, if-else included.

    @ben_lubar said:

    If assignment doesn't return the value on the right hand side, it shouldn't be an expression.

    And if << doesn't shift bits, it shouldn't be <<.



  • @Gaska said:

    In Rust, they're all equivalent

    I'd be worried if os.Exit(0) did the same thing as reaching the end of a function.


  • Banned

    Wait, no. I wasn't reading carefully. Non-returning functions are declared like fn foo() -> !, and then they need to end with panic!() or a diverging function on all control paths.



  • Is there recover!() or does panic!() just call os.Exit?


  • BINNED

    @Gaska said:

    panic!()

    I'm apparently ahead of the curve: I didn't even start learning Rust and that's all I could think about all this time reading the code.


  • Banned

    @ben_lubar said:

    Is there recover!() or does panic!() just call os.Exit?

    It's equivalent to throwing uncaught exception. There's no recovering, no catching, no nothing - you can only put a panic handler, do some stuff, and continue to shit yourself.



  • Sounds like the - operator from HQ9+-


  • Java Dev

    I must admit I don't see the value of having variables with explicit type (). Even if you're allowing a template to be filled in with () to allow Map<T,()>, an explicit non-template () should probably be a compiler warning at least.


  • Banned

    @PleegWat said:

    I must admit I don't see the value of having variables with explicit type ().

    Me neither.

    @PleegWat said:

    template

    generic*


  • Java Dev

    @Gaska said:

    @PleegWat said:
    template

    generic*

    Sorry


  • Discourse touched me in a no-no place

    @tar said:

    I'm pronouncing it void, which it what it should've been called.

    You might be better off using the name unit, at least for the type, since that's what the equivalent thing is called in SML.



  • It's also called Unit in Cool, with the added bonus that the syntax for the Unit value is (). No, there aren't any tuples in the language. It's just ().


  • BINNED

    @ben_lubar said:

    Cool

    Damn it ben, every fucking time I manage to repress the memory...



  • There's apparently a new version of the language out this year. I should <forget to> read about it.


  • Banned

    This unit type, also written as (), was actually a thing in Rust until few months ago, when they decided they don't need this unit type if they can have empty tuples.



  • @Gaska said:

    when they decided they don't need this unit type if they can have empty tuples that error out when you try to do anything with them.

    FTFY



  • Alright, shall we split the endless discussion of ()/void/unit/empty struct/fucking nothing off into its own thread now? KTHXBYE



  • @tar said:

    splitJeff

    no


  • Banned

    @ben_lubar said:

    that error out when you try to do anything with them

    Empty tuples don't error when you store them, when you return them, when you (debug-)print them, when you compare them, when you instantiate them, when you pass them around. They implement all basic traits, like Default or Clone, and also, interestingly, Rand. As in, you can get a random empty tuple using a RNG of your choice.



  • Whoa, can I also get a random empty struct?

    I wonder if I have enough system entropy for both…



  • @ben_lubar said:

    no

    Alright then, I guess I'll start a new rust thread later then.


  • Banned

    @ben_lubar said:

    Whoa, can I also get a random empty struct?

    use std::rand::Rand;
    use std::rand::Rng;
    
    struct MyEmptyStruct;
    
    impl Rand for MyEmptyStruct {
        fn rand<R>(rng: &mut R) -> Self
          where R: Rng {
            // do something useful here
            MyEmptyStruct
        }
    }
    


  • @ben_lubar said:

    Is there recover!()

    benzodiazepine!() can provide symptomatic relief.



  • I can (just about) wrap my head around what closures are.

    Closures are easiest to think about in terms of syntax and scope instead of memory. Consider a language where braces define scope. And consider:

    {
      { a = 1; }
      { b = 1; }
    }
    

    Effectively, braces define a tree, and in this case, the 'smallest' node that contains a is distinct from the smallest node that contains b. Easy enough. Now, what is the smallest node that contains them all? In this case, it's the root of the tree. It is the closure of the nodes.

    In a language "with closures", it just means that you are always able to use variables in higher nodes. The compiler computes the smallest node above all of the variables you mention. The internals are pretty boring unless you're writing a compiler.

    You can reify this idea with an operator.



  • As for how closure lifetime is relevant (you basically have to think about memory if you want to Rust), I played around a bit with @tar's make_closure function a bit, and I think I've found an example that can illuminate. Note the nested scope in which the closure is created; try to guess why it's necessary.

    #![feature(box_syntax)]
    
    fn make_closure(v: &mut i32) -> Box<FnMut(i32)> {
        box move |a| { 
            let t = *v + a; 
            println!("{} + {} = {}" , * v , a , t);
            *v = t;
        }
    }
    
    fn main() {
        let mut x = 1;
        {
            let mut c = make_closure(&mut x);
            c(2);
            c(4);
        }
        println!("      = {}" , x);
    }
    
    

    Hint1: There does exist a shared reference type in Rust; &mut x is not it.
    Hint2: As I understand it, lifetimes are basically Rust's solution to the funarg problem.



  • I can't get your closure to compile—it objects to trying to write out through *v:

    test2.rs:7:9: 7:15 error: cannot assign to data in a captured outer variable in an `Fn` closure
    test2.rs:7         *v = t;
                       ^~~~~~
    

    It compiles and 'works' with that line commented out though...



  • I think you need to change box move |a| to box move |&mut: a| due to your compiler version, as mentioned upthread:

    @Buddy said:

    |&mut:| is now obsolete; they want you to let them infer the closure type all by their self.

    This is what I'm using.



  • package main
    
    import "fmt"
    
    func Adder() func(int) int {
    	var n int
    	return func(x int) int {
    		n += x
    		return n
    	}
    }
    
    func main() {
    	a := Adder()
    	fmt.Println(a(2))
    	fmt.Println(a(4))
    }
    


  • That's garbage [spoiler]collected[/spoiler]

    More to the point: you have completely missed the point: this is your example in Rust:

    #![feature(box_syntax)]
    
    fn accumulator<'a>() -> Box<FnMut(i32) -> i32 + 'a> { //rust can't infer lifetimes for functions that don't take a reference.
        let mut n = 0;
        box move |a| { 
            n += a;
            n
        }
    }
    
    fn main() {
        let mut c = accumulator();
        println!("{}", c(2));
        println!("{}", c(4));
    }
    


  • Fuck this I am now flagging all Go bullshit in this thread as offtopic.



  • @Buddy said:

    I think you need to change box move |a| to box move |&mut: a| due to your compiler version, as mentioned upthread:

    This is what I'm using.

    I thought I had tried that, but nevertheless. I'm using the 1.0.0-alpha, but I'll see if I can translate my closure code to run on your compiler, so I can minimize the differences between them...



  • Barebones Game of Life:

    use Cell::{Dead, Alive};
    
    const CELL_WIDTH: usize = 16;
    const CELL_HEIGHT: usize = 10;
    
    
    #[derive(Copy)]
    #[derive(Show)]
    enum Cell {
        Dead,
        Alive,
    }
    
    
    type Cells = [[Cell; CELL_WIDTH]; CELL_HEIGHT];
    
    struct Grid {
        cells: Cells,
    }
    
    
    struct Life {
        grid: Grid,
    }
    
    
    impl Cell {
        fn update(self, cell_count: usize) -> Cell {
    
            match (self, cell_count) {
                (Dead, 3) => Alive,
                (Alive, 2) => Alive,
                (Alive, 3) => Alive,
                (_, _) => Dead,
            }
        }
    
        fn is_alive(self) -> bool {
            match self {
                Dead => false,
                Alive => true,
            }
        }
    }
    
    
    impl Grid {
        fn new() -> Grid {
            Grid { cells: [[Dead; CELL_WIDTH]; CELL_HEIGHT] }
        }
    
        fn cellx(&self, x: isize, y: isize) -> (usize, usize) {
            let rx = (CELL_WIDTH + x as usize) % CELL_WIDTH;
            let ry = (CELL_HEIGHT + y as usize) % CELL_HEIGHT;
    
            (rx, ry)
        }
    
        pub fn set(&mut self, x: isize, y: isize, val: Cell) {
            let (rx, ry) = self.cellx(x, y);
            self.cells[ry][rx] = val;
        }
    
        pub fn get(&self, x: isize, y: isize) -> Cell {
            let (rx, ry) = self.cellx(x, y);
            self.cells[ry][rx]
        }
    }
    
    
    impl Life {
    
        fn new() -> Life {
            Life { grid: Grid::new() }
        }
    
        fn print(&self) {
            let mut border = "".to_string();
            for i in 0..(CELL_HEIGHT) {
                let mut line = "".to_string();
    
                for j in 0..(CELL_WIDTH) {
                    let v = self.get_cell(j as isize, i as isize);
                    line.push_str(
                        match v {
                            Dead => "\u{00b7}",
                            Alive => "\u{0002}",
                        });
                    if 0 == i {
                        border.push_str("-");
                    }
                }
                if 0 == i {
                    println!("+{}+", border);
                }
                println!("|{}|", line)
            }
            println!("+{}+", border);
        }
    
        pub fn set_cell(&mut self, x: isize, y: isize, val: Cell) {
            self.grid.set(x, y, val);
        }
    
        pub fn get_cell(&self, x: isize, y: isize) -> Cell {
            self.grid.get(x, y)
        }
    
    
        fn neighours(&self, x: isize, y: isize) -> [(isize, isize); 8] {
            [(x - 1, y - 1), (x, y - 1), (x + 1, y - 1),
                (x - 1, y), (x + 1, y),
                (x - 1, y + 1), (x, y + 1), (x + 1, y + 1)]
        }
    
    
        fn cell_count(&self, x: isize, y: isize) -> usize {
            let mut result = 0;
            for &(x, y) in self.neighours(x, y).iter() {
                if self.get_cell(x, y).is_alive() {
                    result = result + 1
                }
            }
            result
        }
    
        fn update(&mut self) {
            let mut new = Grid::new();
            for i in 0..(CELL_HEIGHT) {
                let y = i as isize;
                for j in 0..(CELL_WIDTH) {
                    let x = j as isize;
                    let v = self.get_cell(x, y);
                    let cell_count = self.cell_count(x, y);
    
                    new.set(x, y, v.update(cell_count));
                }
            }
            self.grid = new;
        }
    }
    
    
    fn main() {
        let mut life = Life::new();
    
        life.set_cell(2, 2, Alive);
        life.set_cell(3, 3, Alive);
        life.set_cell(1, 4, Alive);
        life.set_cell(2, 4, Alive);
        life.set_cell(3, 4, Alive);
    
        life.set_cell(9, 6, Alive);
        life.set_cell(10, 6, Alive);
        life.set_cell(11, 6, Alive);
        life.set_cell(11, 7, Alive);
        life.set_cell(10, 8, Alive);
    
        life.print();
    
        for _ in 0..10 {
            println!("");
            life.update();
            life.print();
        }
    }
    

    ASCII gliders!

    +----------------+
    |················|
    |················|
    |··☻·············|
    |···☻············|
    |·☻☻☻············|
    |················|
    |·········☻☻☻····|
    |···········☻····|
    |··········☻·····|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |·☻·☻············|
    |··☻☻············|
    |··☻·······☻·····|
    |··········☻☻····|
    |·········☻·☻····|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |···☻············|
    |·☻·☻············|
    |··☻☻······☻☻····|
    |·········☻·☻····|
    |···········☻····|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |··☻·············|
    |···☻☻···········|
    |··☻☻······☻☻····|
    |···········☻☻···|
    |··········☻·····|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |···☻············|
    |····☻···········|
    |··☻☻☻·····☻☻☻···|
    |············☻···|
    |···········☻····|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |················|
    |··☻·☻······☻····|
    |···☻☻······☻☻···|
    |···☻······☻·☻···|
    |················|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |················|
    |····☻······☻☻···|
    |··☻·☻·····☻·☻···|
    |···☻☻·······☻···|
    |················|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |················|
    |···☻·······☻☻···|
    |····☻☻······☻☻··|
    |···☻☻······☻····|
    |················|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |················|
    |····☻······☻☻☻··|
    |·····☻·······☻··|
    |···☻☻☻······☻···|
    |················|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |············☻···|
    |············☻☻··|
    |···☻·☻·····☻·☻··|
    |····☻☻··········|
    |····☻···········|
    |················|
    |················|
    +----------------+
    
    +----------------+
    |················|
    |················|
    |················|
    |············☻☻··|
    |···········☻·☻··|
    |·····☻·······☻··|
    |···☻·☻··········|
    |····☻☻··········|
    |················|
    |················|
    +----------------+
    

  • Banned

    @tar said:

    ASCII gliders

    @tar said:

    |·········☻☻☻····|

    Yep, totally ASCII.



  • @Gaska said:

    @tar said:
    |·········☻☻☻····|

    Yep, totally ASCII.

    "cmd.exe default codepage characters which happen to copy/paste into Discource" Gliders, then...



  • Sorry, here's a revised version:

    package main
    
    import "fmt"
    
    func Adder(n *int) func(int) int {
    	return func(x int) int {
    		*n += x
    		return *n
    	}
    }
    
    func main() {
    	n := 1
    	a := Adder(&n)
    	fmt.Println(a(2))
    	fmt.Println(a(4))
    }
    

  • BINNED

    @Gaska said:

    Yep, totally ASCII.

    Also, got this while looking for the correct codepage...

    Someone "broke" the googles. Kudos.


  • Banned

    @Onyx said:

    Someone "broke" the googles. Kudos.

    Composing Unicode characters at their finest.



  • So they have until May 15th to get their documentation ducks in a row.


  • Discourse touched me in a no-no place

    @blakeyrat said:

    So they have until May 15th to get their documentation ducks in a row.

    Sounds like they're about like this right now with that:

    https://dinascitywildlife.files.wordpress.com/2012/03/dsc_2796.jpg



  • @Gaska said:

    You might try to learn some graphical library instead of working within terminal, though.

    Is there a rust binding for some GUI library yet though? Last week I tried to look at crates.io, but couldn't find anything reasonable. Some for OpenGL drawing, but nothing with widgets and layouts and such. Don't know whether it does not exist or just does not have sufficiently searchable description.

    That reminds me, having a central place where to look for libraries is certainly a must and it's good they have it, but the naming scheme CPAN has had since ages is a nice touch. Why doesn't anybody (and this is not just crates.io — places like PyPI don't have it either) follow?


  • Discourse touched me in a no-no place

    @Bulb said:

    That reminds me, having a central place where to look for libraries is certainly a must and it's good they have it, but the naming scheme CPAN has had since ages is a nice touch. Why doesn't anybody (and this is not just crates.io — places like PyPI don't have it either.

    Quite apart from the fact that part of your sentence seems absent (I'm a little inclined to do that too), could you explain what the naming scheme is? It's Friday night here; I'm not up to comprehending it by just visiting the site and poking around. :)


Log in to reply