RUST Discussion



  • OK, I've attached a solver to my rendering engine. Shouldn't take too long to get this code into a presentable state...

    
      01    ||    ||  
      02    ||    ||  
      03    ||    ||  
      04    ||    ||  
      05    ||    ||  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      02    ||    ||  
      03    ||    ||  
      04    ||    ||  
      05    ||    01  
    _/||\__/||\__/||\_
    
    Move from 0 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      03    ||    ||  
      04    ||    ||  
      05    02    01  
    _/||\__/||\__/||\_
    
    Move from 2 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      03    ||    ||  
      04    01    ||  
      05    02    ||  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      04    01    ||  
      05    02    03  
    _/||\__/||\__/||\_
    
    Move from 1 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      01    ||    ||  
      04    ||    ||  
      05    02    03  
    _/||\__/||\__/||\_
    
    Move from 1 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      01    ||    ||  
      04    ||    02  
      05    ||    03  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    01  
      04    ||    02  
      05    ||    03  
    _/||\__/||\__/||\_
    
    Move from 0 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    01  
      ||    ||    02  
      05    04    03  
    _/||\__/||\__/||\_
    
    Move from 2 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      ||    01    02  
      05    04    03  
    _/||\__/||\__/||\_
    
    Move from 2 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      02    01    ||  
      05    04    03  
    _/||\__/||\__/||\_
    
    Move from 1 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      01    ||    ||  
      02    ||    ||  
      05    04    03  
    _/||\__/||\__/||\_
    
    Move from 2 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      01    ||    ||  
      02    03    ||  
      05    04    ||  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      02    03    ||  
      05    04    01  
    _/||\__/||\__/||\_
    
    Move from 0 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      ||    02    ||  
      ||    03    ||  
      05    04    01  
    _/||\__/||\__/||\_
    
    Move from 2 --> 1
    
      ||    ||    ||  
      ||    01    ||  
      ||    02    ||  
      ||    03    ||  
      05    04    ||  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    01    ||  
      ||    02    ||  
      ||    03    ||  
      ||    04    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      ||    02    ||  
      ||    03    ||  
      01    04    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      ||    03    02  
      01    04    05  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    01  
      ||    03    02  
      ||    04    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    01  
      ||    ||    02  
      03    04    05  
    _/||\__/||\__/||\_
    
    Move from 2 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      ||    01    02  
      03    04    05  
    _/||\__/||\__/||\_
    
    Move from 2 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      02    01    ||  
      03    04    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      01    ||    ||  
      02    ||    ||  
      03    04    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      01    ||    ||  
      02    ||    04  
      03    ||    05  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    01  
      02    ||    04  
      03    ||    05  
    _/||\__/||\__/||\_
    
    Move from 0 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    01  
      ||    ||    04  
      03    02    05  
    _/||\__/||\__/||\_
    
    Move from 2 --> 1
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    ||  
      ||    01    04  
      03    02    05  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    03  
      ||    01    04  
      ||    02    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 0
    
      ||    ||    ||  
      ||    ||    ||  
      ||    ||    03  
      ||    ||    04  
      01    02    05  
    _/||\__/||\__/||\_
    
    Move from 1 --> 2
    
      ||    ||    ||  
      ||    ||    02  
      ||    ||    03  
      ||    ||    04  
      01    ||    05  
    _/||\__/||\__/||\_
    
    Move from 0 --> 2
    
      ||    ||    01  
      ||    ||    02  
      ||    ||    03  
      ||    ||    04  
      ||    ||    05  
    _/||\__/||\__/||\_
    
    


  • Alright then, Tower of Hanoi solver in Rust. (See previous post for output.)

    • Currently hardcoded to solve the case of 5 pegs on 3 poles, should be fixable. The initial state of the Scene is hardcoded in Scene::new() (create poles, stuff pegs on the first pole), and the HanoiSolver is initialized to operate on that state.
    • Scene is responsible for drawing the current state of the simulation (from show(), using println!() macro). move_peg() attempts a valid move of a peg from one pole to another, returning true if it can, or false if it can't. (The solver only attempts valid moves if its set up correctly so this should be a non-issue, but this could support e.g. a human player.)
    • The scene owns a Vec of Poles—each Pole owns a Vec of Pegs, and tracks the smallest (topmost) Peg. (Not sure the struct Peg is buying me much...)
    • There are a few warnings generated by the code building output strings in Scene::show(), but string manipulation in Rust seems to be in a pretty incredible state at the moment anyway.
    • I'm going as far as to say this is semi-idiomatic code—I'm still adding/removing mut/ref/& in different places to get things to compile, and breaking objects down in some places to avoid issues with borrowing, but it's starting to feel like it would eventually make sense...
    • I quite like the impl Iterator for HanoiSolver syntax for implementing traits, that seems nice. * The HanoiSolver just builds all the states it wants to visit in its new function and stores them in a Vec of (from, to) move co-ordinates, which makes the implementation of next() dirt simple.
    • Not sure I like the mandatory self. on all member variables, I've been using let to try and bind stuff on the LHS to self on the RHS to avoid this in some places...
    • Rust is.. very terse..., what with fn, mut, ref, Vec, impl, and so on. I kind of prefer to see full words when I write code, so I'm not sure how fond of this I am. At least they're all fairly self-explanatory abbreviations though.
    • Don't even ask about usize vs u32 (vs i32...)
    • That whole thing about using ; at the end of a block to return () ("void"), vs implicity returning values which don't have a ; after them—that feels completely natural and easy to use, and a lot less complex than I just made it sound...
    //------------------------------------------------------------------------------
    
    const PEG_COUNT: usize = 5;
    const POLE_COUNT: usize = 3;
    const NO_PEG: u32 = 0xffffffff;
    
    
    struct Peg(u32);
    
    
    struct Pole {
        pegs: Vec<Peg>,
        smallest: u32,
    }
    
    
    struct Scene {
        poles: Vec<Pole>,
    }
    
    
    impl Pole {
    
        fn new() -> Pole {
            Pole {
                pegs: Vec::with_capacity(PEG_COUNT),
                smallest: NO_PEG,
            }
        }
    
        fn push(&mut self, p: Peg) -> bool {
            let Peg(v) = p;
    
            if v < self.smallest {
                self.pegs.push(p);
                self.smallest = v;
                true
    
            } else {
                println!("ERR: tried to push size {} onto pole {}.", v, self.smallest);
                false
            }
        }
    
        fn pop(&mut self) -> Option<Peg> {
            let mut smallest = NO_PEG;
            let mut pegs = &mut self.pegs;
            let result = pegs.pop();
    
            for i in 0..(pegs.len()) {
                let Peg(v) = pegs[i];
                if v < smallest {
                    smallest = v
                }
            }
    
            self.smallest = smallest;
            result
        }
    }
    
    
    impl Scene {
    
        fn new() -> Scene {
            let mut result = Scene {
                poles: Vec::with_capacity(POLE_COUNT),
            };
    
            for _ in 0..(POLE_COUNT) {
                result.poles.push(Pole::new());
            };
    
            for j in 0..(PEG_COUNT) {
                result.poles[0].push(Peg((PEG_COUNT - j) as u32));
            };
    
            result
        }
    
        fn move_peg(&mut self, from: usize, to: usize) -> bool {
            if let Some(Peg(v)) = self.poles[from].pop() {
                if self.poles[to].push(Peg(v)) {
                    return true
                } else {
                    self.poles[from].push(Peg(v));
                }
            }
            false
        }
    
        fn get(&self, pole: usize, peg: usize) -> Option<&Peg> {
            let poles = &self.poles;
    
            if poles.len() > pole {
                let pegs = &poles[pole].pegs;
    
                if pegs.len() > peg {
                    return Some(&pegs[peg])
                }
            }
            None
        }
    
        fn show(&self) {
            println!("");
            for i in 0..(PEG_COUNT) {
                let mut string = "".to_string();
    
                for j in 0..(POLE_COUNT) {
                    match self.get(j, (PEG_COUNT-1)-i) {
    
                        Some(&Peg(p)) => {
                            let fmt = format!("  {:02}  ", p).to_string();
                            string.push_str(fmt.as_slice());
                        }
    
                        None => {
                            string.push_str("  ||  ");
                        }
                    }
                }
    
                println!("{}", string);
            }
            let mut string = "".to_string();
            for _ in 0..(POLE_COUNT) {
                string.push_str("_/||\\_")
            }
            println!("{}", string);
            println!("");
        }
    }
    
    
    //------------------------------------------------------------------------------
    
    struct HanoiMove {
        from: usize,
        to: usize,
    }
    
    
    struct HanoiState {
        n: usize,
        from: usize,
        to: usize,
        via: usize,
    }
    
    
    struct HanoiSolver {
        step: usize,
        route: Vec<HanoiMove>,
    }
    
    
    impl HanoiState {
    
        fn new(n: usize, from: usize, to: usize, via: usize) -> HanoiState {
            HanoiState { n: n, from: from, to: to, via: via }
        }
    
        fn iter(&self, out: &mut Vec<HanoiMove>) {
            let &HanoiState { n, from, to, via } = self;
            if n > 0 {
                HanoiState::new(n - 1, from, via, to).iter(out);
                out.push(HanoiMove { from: from, to: to });
                HanoiState::new(n - 1, via, to, from).iter(out);
            }
        }
    }
    
    
    impl HanoiSolver {
    
        fn new(n: usize, from: usize, to: usize, via: usize) -> HanoiSolver {
            let mut result = HanoiSolver {
                step: 0,
                route: Vec::new(),
            };
            let state = HanoiState::new(n, from, to, via);
            state.iter(&mut result.route);
            result
        }
    }
    
    
    impl Iterator for HanoiSolver {
        type Item = HanoiMove;
        fn next(&mut self) -> Option<HanoiMove> {
    
            let &mut HanoiSolver { step, ref route } = self;
    
            if step < route.len() {
                let HanoiMove{ from, to } = route[step];
                self.step += 1;
                return Some(HanoiMove { from: from, to: to })
            }
            None
        }
    }
    
    
    //------------------------------------------------------------------------------
    
    fn main() {
    
        let mut scene = Scene::new();
        let mut solver = HanoiSolver::new(PEG_COUNT, 0, 2, 1);
    
        scene.show();
    
        while let Some(HanoiMove { from, to }) = solver.next() {
    
            println!("Move from {} --> {}", from, to);
            scene.move_peg(from, to);
            scene.show();
        }
    }
    
    
    

  • Banned

    @tar said:

    It would probably never have occurred to me to try and put a let in the test expression of an if statement

    Actually, if let has nothing to do with either if or let - it's a separate construct more akin to match. AFAIK, it's even implemented to translate into match statement.

    @tar said:

    Personally I find the use of self instead of this to be much more upsetting.

    Me too. Also, it's explicit. I'd much rather have static fn and mut fn member functions. I blame Python for these two.

    @Buddy said:

    So, typing out a quick paragraph of your distilled understanding of closures gained from (...) 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.

    My goal wasn't to convince anyone of anything. I just wanted to explain how closures work.

    @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.

    Not related? Enum without fields works exactly like enum in other languages. And enum with fields is so similar to the regular enum they didn't think a separate keyword is necessary.

    @Buddy said:

    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.

    If it was someone else accusing me of treating everyone around like idiots just because I said "it's simple", I would argue the same way.


  • Discourse touched me in a no-no place

    @Gaska said:

    And enum with fields is so similar to the regular enum they didn't think a separate keyword is necessary.

    Except that now you've got two instances that have different contents but are the same in enumeration terms. That is different from every other language out there (that has enums; some don't bother). Taking a term that is very well understood elsewhere and reinterpreting it to mean something else is inevitably a source of confusion, even if that is a job that sometimes needs to be done.


  • Banned

    @dkf said:

    Except that now you've got two instances that have different contents but are the same in enumeration terms.

    Enum with no fields can be thought a special case of enum with fields.

    @dkf said:

    That is different from every other language out there (that has enums; some don't bother).

    Rather than different, I'd say generalized for more use cases.


  • Discourse touched me in a no-no place

    @Gaska said:

    Rather than different, I'd say generalized for more use cases.

    It's different. Different isn't always bad, but it does make more work for people teaching the language to others.


  • Banned

    Considering how strict the lifetime system and borrow checking are, tagged-unions-named-enums is the least of teachers' problems. It's the same difficulty as "why the fuck can't I just return int goddammit!!!".


  • Discourse touched me in a no-no place

    I think when it comes to “teachers' problems” right now, the general underdocumentedness of it is a bit more fundamental. ;)


  • Banned

    Well, lack of documentation is more of a problem for teachees than teachers. If you go to their IRC, there are plenty people there who are very knowledgable about the language - much better source of information than the official docs (sadly; also, currently - might change in future). It's kinda like, before 2011, no C++ tutorial would ever mention shared_ptr, but everyone knew that you should use it instead of raw pointer, always.


  • Discourse touched me in a no-no place

    @Gaska said:

    Well, lack of documentation is more of a problem for teachees than teachers.

    I've done some teaching. Lack of documentation is a huge problem…


  • Banned

    Not if you can keep everything in mind. And, apparently, Rust people can. Which is very impressive, but also raises question about their private lives (or lack of thereof).


  • I survived the hour long Uno hand

    @Gaska said:

    if let has nothing to do with either if or let

    QF :wtf:


  • Banned

    Yeah, my reaction to that revelation too. It would be awesome to do if let Some(Foo(_, 5)) = x && t > 10, but no can do.



  • Like a Raspberry Pi! RIGHT GUYS!? RIGHT??? Raspberry Pi!??!???!??!??! LOLOLLOL

    Seriously though, why are you defending this shit, Gaska? Everything I've learned about Rust in this thread has led me to the opinion that its an awful language with ass-backwards priorities.


  • Banned

    @blakeyrat said:

    Seriously though, why are you defending this shit, Gaska?

    I'm not defending. I'm just clarifying. Stating that it's not as much a problem to teach others the language as it is to teach yourself the language is kind of anti-advertisement, don't you think?

    @blakeyrat said:

    Everything I've learned about Rust in this thread has led me to the opinion that its an awful language with ass-backwards priorities.

    That's because you think everything should be managed. It's not a wrong mindset in general - but it's wrong in Rust.



  • @Gaska said:

    That's because you think everything should be managed.

    I think:

    1. You shouldn't race headlong into creating the same documentation nightmare of (say) OpenGL. Reproducing their 20-years'-worth of confusion in only a couple years.

    2. You shouldn't force the programmer to spend ages thinking about bullshit only the compiler cares about. Unless there's a very very clear case for saving the programmer's time later on.

    3. Open source development sucks. The people working on Rust might be good at programming language design, but they're fucking awful at understanding human psychology and that'll doom the language to zero adoption.

    It has nothing to do with "everything should be managed", although I guess point 2 could kind of be read that way.


  • Banned

    @blakeyrat said:

    1) You shouldn't race headlong into creating the same documentation nightmare of (say) OpenGL. Reproducing their 20-years'-worth of confusion in only a couple years.

    AFAIK they understand this and they'll have all the docs done by the time of final 1.0 release.

    @blakeyrat said:

    2) You shouldn't force the programmer to spend ages thinking about bullshit only the compiler cares about. Unless there's a very very clear case for saving the programmer's time later on.

    Managed world doesn't have to deal with uninitialized variables and dangling pointers.

    @blakeyrat said:

    3) Open source development sucks.

    It's good you put it at the beginning instead of the end - I can safely assume that the rest is prejudicial bullshit and not read it. You know what? I actually read it. And my assumption was right.



  • @Gaska said:

    AFAIK they understand this and they'll have all the docs done by the time of final 1.0 release.

    Unless they have a magical brush they can use to scour all the obsolete documentation from the web, this isn't enough.

    @Gaska said:

    It's good you put it at the beginning instead of the end

    Wow. I knew some cultures read right-to-left but I didn't know any read bottom-to-top.


  • ♿ (Parody)

    @Gaska said:

    AFAIK they understand this and they'll have all the docs done by the time of final 1.0 release.

    Blakey isn't generally interested in the nitty gritty details of causality and temporality and reality.

    @blakeyrat said:

    Unless they have a magical brush they can use to scour all the obsolete documentation from the web, this isn't enough.

    See?


  • Banned

    @blakeyrat said:

    Unless they have a magical brush they can use to scour all the obsolete documentation from the web, this isn't enough.

    Sadly, MIT refused to take down their outdated docs. But I think they could raise the issue to Google itself to not list it on the first page.

    @blakeyrat said:

    Wow. I knew some cultures read right-to-left but I didn't know any read bottom-to-top.

    1. Chinese can be read both left-to-right and right-to-left, and both top-to-bottom and bottom-to-top, and in any combination of the two.
    2. I was referring to local beginning - ie. the beginning of bullet point. And I only consider this single bullet point prejudicial.

  • Banned

    @boomzilla said:

    Blakey isn't generally interested in the nitty gritty details of causality and temporality and reality.

    There's official docs maintained by the original authors of the language, and there's the whole uncontrolled mess of the internets and textbooks. Blaming the authors for what's around the internets is like blaming Obama for school shootings.


  • ♿ (Parody)

    @Gaska said:

    blaming Obama for school shootings.

    I could believe it if we were talking about golf schools.


  • Banned

    Perfect occasion for negligent discharge.


  • Discourse touched me in a no-no place

    I agree with points 1 and 2, and the second sentence of point 3. It's not “open source” though; just the way certain types of teams work. I would hesitate to claim that it's a special feature of open source; closed teams can get pretty dysfunctional (especially in large organisations) and not all open teams are broken.


  • Java Dev

    @Gaska said:

    It's the same difficulty as "why the fuck can't I just return int goddammit!!!".

    Actually, as I understand the docs, you can just return int. And it's suggested you can return even large structures by value and it'll be fast - I assume that means that under water the caller is providing the memory space to the callee so no copy is needed.


  • Banned

    @PleegWat said:

    Actually, as I understand the docs, you can just return int.

    http://is.gd/zE8sJm

    By the time Rust hits 1.0, this warning will become error, with workaround removed completely.


  • Java Dev

    Ah, so. Yeah. Thought you were referring to the whole problem with returning references with unknown lifetimes.



  • @Gaska said:

    I just wanted to explain how closures work.

    If someone here is having a hard time getting to the bottom of something, it is generally a safe bet that they are not struggling with the simple part of it.


  • ♿ (Parody)

    @Buddy said:

    If someone here is having a hard time getting to the bottom of something, it is generally a safe bet that they are not struggling with the simple part of it.

    I have experienced, on both sides of the equation, situations where some simple assumption was incorrect and causing the problems. Once pointed out, things became much clearer.



  • I'll have another look for Rust docs over lunch. If I find anything, I'll follow up...



  • @tar said:

    Rust docs

    @tar said:
    TDEMSYR

    OK, I read over the Ownership section of the Rust Book, and I managed to make my closures work right...

    fn make_closure<'a>(start: i32) -> Box<FnMut(i32) -> i32 + 'a> {
    
        let mut v = start;
    
        box move |&mut:a: i32| -> i32 {
            let t = v + a;
            println!("{} + {} = {}", v, a, t);
            v = t;
            t
        }
    }
    
    

    EDITED to fix return value



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


  • BINNED

    @Buddy said:

    they want you to let them infer the closure type all by their self.

    Bad programmer! Stop thinking! BAD!


  • Banned

    @tar said:

    box move |&mut🅰 i32| -> i32 {

    Your lambda doesn't return anything, yet you declared it to return i32. Did you even try to compile your code?

    @Onyx said:

    Bad programmer! Stop thinking! BAD!

    Well, the syntax was very ugly. Even for natively compiled languages standards.


  • BINNED

    @Gaska said:

    Well, the syntax was very ugly. Even for natively compiled languages standards.

    True. But instead of making syntax nicer they decided they'll just fix it in post


  • Banned

    Except the feature wasn't supposed to be there at all in the first place - it was meant to be all inferred from the start, but the initial implementation wasn't working in all cases and thus an ugly hack was implemented.



  • @Gaska said:

    Your lambda doesn't return anything, yet you declared it to return i32. Did you even try to compile your code?

    Of course I compiled it. Isn't v = t (i.e. the value of t) the return value? That's what I would've expected...


  • Banned

    It isn't, for two reasons - assignment returns (), not the value, and you put a semicolon at the end.



  • @Gaska said:

    It isn't, for two reasons

    Oh. I wonder why that's compiling...

    @Gaska said:

    assignment returns (), not the value

    That's stupid.

    @Gaska said:

    and you put a semicolon at the end.

    I'm stupid.

    I think I did have v = t; t originally.

    Seriously though, no way to take the value of an assigment? Fuckin' nanny state programming languages these days...

    OK, I edited in a solitaty t at the end of the closure. (Not that we're actually using the return value for anything anyway...)


  • Banned

    @tar said:

    That's stupid.

    It's not. Value-y assignment exists exclusively in C and only leads to either extremely unreadable code or nasty little bugs. Did you ever have to deal with a code that uses assignment in if condition, where it's not a typo but actually the intended behavior? I did.

    It made sense in C because that's how assembler works. We're long past assembler-as-general-purpose-language times now.



  • My problem with it is that if we keep removing or neutering language features because some hypothetical idiot might have trouble with them, then eventually we end up with no language at all.

    We can invent a hypothetical idiot who has trouble with anything. At some point you have to just say, damn it, let's just assume everyone worth supporting will reach a level of competence, and stop giving experienced users the shaft for the perceived benefit of 'new users'.

    See PHP for an example of the logical endpoint of that thought process...


  • I survived the hour long Uno hand

    @Gaska said:

    Value-y assignment exists exclusively in C

    False

    @Gaska said:

    Did you ever have to deal with a code that uses assignment in if condition

    Yes



  • OK, here's a fun little Rust puzzle. This code doesn't compile, but why? Does it not compile for valid reasons or invalid reasons? DISCUSS!

    
    
    fn main() {
    
        let a = 1;
        let mut b = 2;
        let c = (b = a);
    
        println!("{} {} {}", a, b, c);
    
    }
    

    (Someone remind me to print the compiler error before I go to work, or we'll be here all day...)



  • @tar said:

    My problem with it is that if we keep removing or neutering language features because some hypothetical idiot might have trouble with them, then eventually we end up with no language at all.

    No, we end up with better, less buggy, software.

    @tar said:

    We can invent a hypothetical idiot who has trouble with anything. At some point you have to just say, damn it, let's just assume everyone worth supporting will reach a level of competence, and stop giving experienced users the shaft for the perceived benefit of 'new users'.

    Right; but that assumed level of competence has to include everybody who will touch your codebase. And a lot of companies hire idiots.

    @tar said:

    See PHP for an example of the logical endpoint of that thought process...

    PHP is pretty much the exact opposite philosophy.


  • ♿ (Parody)

    @tar said:

    My problem with it is that if we keep removing or neutering language features because some hypothetical idiot might have trouble with them, then eventually we end up with no language at all.

    That's not exactly wrong, but there's not really anything hypothetical with this situation.



  • @blakeyrat said:

    Right; but that assumed level of competence has to include everybody who will touch your codebase. And a lot of companies hire idiots.

    My proposed solution is to start my own company which doesn't hire idiots. With blackjack! And hookers!

    @tar said:

    PHP is pretty much the exact opposite philosophy.

    I don't know, I thought the PHP developers were on record as being primarily concerned with making things 'accessible'? Which is why PHP is really easy to get started with, but has all kinds of crazy second-order behaviours once features of the language start interacting with each other in unanticipated ways...



  • PHP may have started that way, but its problems really started when they went for the "kitchen sink" philosophy and just started throwing everything in there.


  • Banned

    @tar said:

    My problem with it is that if we keep removing or neutering language features because some hypothetical idiot might have trouble with them, then eventually we end up with no language at all.

    Removing language features can have one of three outcomes:

    1. Crippling functionality of the language - because what was possible (or equivalently, easier to do) before, now is impossible (or very hard).
    2. Cleaning up the language - because the functionality wasn't very good anyway, or rarely useful, or collided with another potential feature.
    3. Make the users write better, more readable code - in this category lies goto, value-y assignments and value-y increments.

    @tar said:

    OK, here's a fun little Rust puzzle. This code doesn't compile, but why? Does it not compile for valid reasons or invalid reasons? DISCUSS!

    The compile error is clear enough. Not a particularly hard puzzle if you're allowed to use compiler.



  • @Gaska said:

    The compile error is clear enough. Not a particularly hard puzzle if you're allowed to use compiler.

    I got this error, and it hurt me:

    error: the trait `core::fmt::String` is not implemented for the type `()`
    

    I'm assuming that that's something they're going to fix at some point? Having my logging code fail to compile because the value I'm trying to log didn't exist doesn't seem like a happy place to be...


  • Banned

    You got it wrong. The value exists. The value is (), of type (), returned by expression "b = a", assigned to variable c. The println! macro depends on types having core::fmt::String trait implemented, and () type doesn't implement it. This is the cause of error.


Log in to reply