Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
sarehu
Apr 20, 2007

(call/cc call/cc)
They didn't kick him out, they acted passive-aggressively towards him until he stopped contributing. After he left, a certain contributor would close issues that he'd opened with bothering to understand them, giving reasons that didn't actually engage with the issue.

With Rust, it's like, instead of just disagreeing with you, a core team member will pop in and insinuate that you're lying.

Edit: Basically me : Rust :: michaelochurch : VC's

sarehu fucked around with this message at 02:27 on May 19, 2015

Adbot
ADBOT LOVES YOU

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
a person can be both right and also a giant dick in how they convey their message. the latter does not excuse the former

also lmao at your garbage hn posts shrughes

Deus Rex
Mar 5, 2005

Suspicious Dish posted:

a person can be both right and also a giant dick in how they convey their message. the latter does not excuse the former

Do you mean the former doesn't excuse the latter?

I agree that the official documentation (or at least "the Book", I can't speak for API docs) is pretty awful. It's written in a conversational style that just feels condescending to me. A few very smart and experienced programmers I know have been put off learning Rust until something like an O'Reilly book is released, because "the Book" is hard to follow, full of weird examples, and sometimes even hard to follow. What's frustrating is that pull requests like these, which do nothing but improve the clarity of a passage, were rejected because the primary docs author refused to accept style input. https://github.com/rust-lang/rust/pull/19929 https://github.com/rust-lang/rust/pull/20439

rust-by-example exists and is much better, but it's hardly a way to learn the language ex nihilo, in my opinion.

triple sulk
Sep 17, 2014



Deus Rex posted:

Do you mean the former doesn't excuse the latter?

I agree that the official documentation (or at least "the Book", I can't speak for API docs) is pretty awful. It's written in a conversational style that just feels condescending to me. A few very smart and experienced programmers I know have been put off learning Rust until something like an O'Reilly book is released, because "the Book" is hard to follow, full of weird examples, and sometimes even hard to follow. What's frustrating is that pull requests like these, which do nothing but improve the clarity of a passage, were rejected because the primary docs author refused to accept style input. https://github.com/rust-lang/rust/pull/19929 https://github.com/rust-lang/rust/pull/20439

rust-by-example exists and is much better, but it's hardly a way to learn the language ex nihilo, in my opinion.

Rust is what happens when you let a bunch of Ruby developers design and document a language (José Valim being an exception) so it's not surprising that they're smug assholes who don't take criticism well. I'm in agreement with you that the conversational tone of "the Book" as it is referred to is dumb. I haven't looked extensively at the documentation in a while but the last I remember it was badly organized, but that may have also been because of the lack of clarity about crate usage at the time.

Deus Rex
Mar 5, 2005

triple sulk posted:

Rust is what happens when you let a bunch of Ruby developers design and document a language (José Valim being an exception) so it's not surprising that they're smug assholes who don't take criticism well. I'm in agreement with you that the conversational tone of "the Book" as it is referred to is dumb. I haven't looked extensively at the documentation in a while but the last I remember it was badly organized, but that may have also been because of the lack of clarity about crate usage at the time.

Out of the many prominent contributors and members of the "core team", I can think of two who are well-known "Ruby programmers". One of them is (was?) paid by Mozilla to work exclusively on documentation and the other was contracted by Mozilla to write the first version of the current incarnation Cargo (which was taken over by superhuman Mozillian acrichto pretty quickly), and now is a non-paid contributor assigned to work on tooling. The first one is the person who didn't accept pull requests on the basis of style; nobody else objected to it because they generally didn't make the quality of documentation their concern after he was contracted. I don't know where you get, like, "a bunch of Ruby developer" from. thestinger/strcat is like the anti-Ruby developer, and he designed practically half of the (good parts) of Rust.

The quality of the introductory and API documentation is probably a blind spot for almost all of the primary contributors to the language and standard libraries, because they already know those things without needing to read the docs (plus they're so busy and whatever). It sounds like with 1.0, and a whole lot of new eyes, the documentation came under more scrutiny and hopefully there will be some improvements in tone and style.

sarehu
Apr 20, 2007

(call/cc call/cc)
You don't have to tone police the docs, thank you.

DONT THREAD ON ME
Oct 1, 2002

by Nyc_Tattoo
Floss Finder
I did some rust this weekend and I will feel pretty convinced that it's going to be a big deal.

I know you were all anxious to get my opinion so there it is.

gonadic io
Feb 16, 2011

>>=

MALE SHOEGAZE posted:

I did some rust this weekend and I will feel pretty convinced that it's going to be a big deal.

I know you were all anxious to get my opinion so there it is.

Quick pick a top library from another language and then write it in Rust! Parsec, lens, an xml parser or something.

Vanadium
Jan 8, 2005

Do they have a commonly used quickcheck yet?

the talent deficit
Dec 20, 2003

self-deprecation is a very british trait, and problems can arise when the british attempt to do so with a foreign culture





Shinku ABOOKEN posted:

Now that I think about it what language design team actually have a woman in it?

Ingela Andin and Siri Hansen on the erlang team.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

gonadic io posted:

Quick pick a top library from another language and then write it in Rust! Parsec, lens, an xml parser or something.

This maybe isn't a bad idea if you want 15 minutes of programmer fame.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

the talent deficit posted:

Ingela Andin and Siri Hansen on the erlang team.

Sara Golemon on Hack.

leftist heap
Feb 28, 2013

Fun Shoe
So what's the best way to install Rust on OSX and get something half portable? Just the official installer? Hand-bomb the official binaries somewhere?

piratepilates
Mar 28, 2004

So I will learn to live with it. Because I can live with it. I can live with it.



I'm trying to learn some Rust since it seems like a pretty rad idea, so far I've been trying to do some simple data structures to figure it all out.

Here's what I have for a binary search tree, it compiles and runs but the insertion doesn't fully work -- it seems to remove all the past changes each time you insert a new node:

http://is.gd/qhiZkq
code:
fn main() {
    let mut butt = BSTNode::new(5);
    println!("{:?}", butt);
    butt.insert(7);
    println!("{:?}", butt);
    butt.insert(2);
    println!("{:?}", butt);
    butt.insert(1);
    butt.insert(3);
    butt.insert(4);
    butt.insert(6);
    butt.insert(8);
    println!("{:?}", butt);

}

#[derive(Debug)]
struct BSTNode {
    value: i32,
    left: Option<Box<BSTNode>>,
    right: Option<Box<BSTNode>>
}

impl BSTNode {
    fn new(value: i32) -> BSTNode {
        BSTNode {
            value: value,
            left: None,
            right: None
        }
    }
    
    fn insert(&mut self, value: i32) {
        match (self.value > value, self.left.take(), self.right.take()) {
            (true, None, _) => self.left = Some(Box::new(BSTNode::new(value))),
            (true, Some(ref mut left), _) => left.insert(value),
            (false, _,  None) => self.right = Some(Box::new(BSTNode::new(value))),
            (false, _, Some(ref mut right)) => right.insert(value),
        }
    }
}
Which prints:

code:
BSTNode { value: 5, left: None, right: None }
BSTNode { value: 5, left: None, right: Some(BSTNode { value: 7, left: None, right: None }) }
BSTNode { value: 5, left: Some(BSTNode { value: 2, left: None, right: None }), right: None }
BSTNode { value: 5, left: None, right: None }
Anyone know how I screwed up?

Also how far off base is everything I did idiomatically-wise?

Also what exactly is 'self.left.take()' doing? It fails compiling without it with the message 'cannot move out of borrowed content' and I somehow googled my way in to using it.

edit: alright well scratch why it doesn't work, take() just replaces the content with a None, which is why my children are disappearing. How do I borrow the self.left and self.right in the match otherwise?

Gaukler
Oct 9, 2012


piratepilates posted:

I'm trying to learn some Rust since it seems like a pretty rad idea, so far I've been trying to do some simple data structures to figure it all out.

Here's what I have for a binary search tree, it compiles and runs but the insertion doesn't fully work -- it seems to remove all the past changes each time you insert a new node:

http://is.gd/qhiZkq
code:
fn main() {
    let mut butt = BSTNode::new(5);
    println!("{:?}", butt);
    butt.insert(7);
    println!("{:?}", butt);
    butt.insert(2);
    println!("{:?}", butt);
    butt.insert(1);
    butt.insert(3);
    butt.insert(4);
    butt.insert(6);
    butt.insert(8);
    println!("{:?}", butt);

}

#[derive(Debug)]
struct BSTNode {
    value: i32,
    left: Option<Box<BSTNode>>,
    right: Option<Box<BSTNode>>
}

impl BSTNode {
    fn new(value: i32) -> BSTNode {
        BSTNode {
            value: value,
            left: None,
            right: None
        }
    }
    
    fn insert(&mut self, value: i32) {
        match (self.value > value, self.left.take(), self.right.take()) {
            (true, None, _) => self.left = Some(Box::new(BSTNode::new(value))),
            (true, Some(ref mut left), _) => left.insert(value),
            (false, _,  None) => self.right = Some(Box::new(BSTNode::new(value))),
            (false, _, Some(ref mut right)) => right.insert(value),
        }
    }
}
Which prints:

code:
BSTNode { value: 5, left: None, right: None }
BSTNode { value: 5, left: None, right: Some(BSTNode { value: 7, left: None, right: None }) }
BSTNode { value: 5, left: Some(BSTNode { value: 2, left: None, right: None }), right: None }
BSTNode { value: 5, left: None, right: None }
Anyone know how I screwed up?

Also how far off base is everything I did idiomatically-wise?

Also what exactly is 'self.left.take()' doing? It fails compiling without it with the message 'cannot move out of borrowed content' and I somehow googled my way in to using it.

edit: alright well scratch why it doesn't work, take() just replaces the content with a None, which is why my children are disappearing. How do I borrow the self.left and self.right in the match otherwise?

I'm quite new to Rust myself so I spent some time wrestling the borrow checker, but the following works: (http://is.gd/nVAEU0)

code:
fn main() {
    let mut butt = BSTNode::new(5);
    println!("{:?}", butt);
    butt.insert(7);
    println!("{:?}", butt);
    butt.insert(2);
    println!("{:?}", butt);
    butt.insert(1);
    butt.insert(3);
    butt.insert(4);
    butt.insert(6);
    butt.insert(8);
    println!("{:?}", butt);

}

#[derive(Debug)]
struct BSTNode {
    value: i32,
    left: Option<Box<BSTNode>>,
    right: Option<Box<BSTNode>>
}

impl BSTNode {
    fn new(value: i32) -> BSTNode {
        BSTNode {
            value: value,
            left: None,
            right: None
        }
    }
    
    fn insert(&mut self, value: i32) {
    
        if self.value > value {
            match self.left {
                Some(ref mut left) => left.insert(value),
                None => self.left = Some(Box::new(BSTNode::new(value))),
            }
        } else {
            match self.right {
                Some(ref mut right) => right.insert(value),
                None => self.right = Some(Box::new(BSTNode::new(value))),
            }
        }
    }
}
Prints:
code:
BSTNode { value: 5, left: None, right: None }
BSTNode { value: 5, left: None, right: Some(BSTNode { value: 7, left: None, right: None }) }
BSTNode { value: 5, left: Some(BSTNode { value: 2, left: None, right: None }), right: Some(BSTNode { value: 7, left: None, right: None }) }
BSTNode { value: 5, left: Some(BSTNode { value: 2, left: Some(BSTNode { value: 1, left: None, right: None }), right: Some(BSTNode { value: 3, left: None, right: Some(BSTNode { value: 4, left: None, right: None }) }) }), right: Some(BSTNode { value: 7, left: Some(BSTNode { value: 6, left: None, right: None }), right: Some(BSTNode { value: 8, left: None, right: None }) }) }
Which looks right by my checking. I THINK the problem was when you do (self.value > value, self.left, self.right), you implicitly create a new Tuple which borrows self.left and self.right, so you can't use them in your match arms.

leftist heap
Feb 28, 2013

Fun Shoe
^^^ pretty much the conclusion I came to. I'm also a Rust newb.

You can also match on self and do roughly the same thing but it's very unwieldy.

Sweeper
Nov 29, 2007
The Joe Buck of Posting
Dinosaur Gum
I'm basically know nothing about rust, but is there any way to "hide" mutability of a struct?

code:
use std::collections::HashMap;

struct Test<'a> {
    map: HashMap<&'a str, u32>
}

impl<'a> Test<'a> {
    fn new() -> Test<'a> {
        return Test {
            map: HashMap::new()
        }
    }

    fn size(&self) -> usize {
        return self.map.keys().count();
    }

    fn add(&self, key: &'a str, count: u32) {  <------ I don't want to have to pass &mut self
        self.map.insert(key, count);
    }

}

fn main() {
    let t = Test::new();

    t.add("test", 1);
    println!("{}", t.size());
}
How do I not pass '&mut self' to the add function, and keep it as &self? I don't want to declare every object as mutable because a map it contains is mutable. I'd like to hide that implementation detail from the consumer...

Also is there any long winded explanation of lifetimes, I'm an idiot and need more words

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Sweeper posted:

I don't want to declare every object as mutable because a map it contains is mutable. I'd like to hide that implementation detail from the consumer...

If you're doing something that modifies your object, you're going to need it to be mutable. This is by design. Having a function that modifies your object out from underneath you despite only taking a read borrow would defeat the entire purpose of the borrow checking and blow all of those safety guarantees out of the water.

Whether a function changes an object isn't an "implementation detail" to be hidden away, it's an inherent part of the contract of that function.

piratepilates
Mar 28, 2004

So I will learn to live with it. Because I can live with it. I can live with it.



Gaukler posted:

I'm quite new to Rust myself so I spent some time wrestling the borrow checker, but the following works: (http://is.gd/nVAEU0)

code:
fn main() {
    let mut butt = BSTNode::new(5);
    println!("{:?}", butt);
    butt.insert(7);
    println!("{:?}", butt);
    butt.insert(2);
    println!("{:?}", butt);
    butt.insert(1);
    butt.insert(3);
    butt.insert(4);
    butt.insert(6);
    butt.insert(8);
    println!("{:?}", butt);

}

#[derive(Debug)]
struct BSTNode {
    value: i32,
    left: Option<Box<BSTNode>>,
    right: Option<Box<BSTNode>>
}

impl BSTNode {
    fn new(value: i32) -> BSTNode {
        BSTNode {
            value: value,
            left: None,
            right: None
        }
    }
    
    fn insert(&mut self, value: i32) {
    
        if self.value > value {
            match self.left {
                Some(ref mut left) => left.insert(value),
                None => self.left = Some(Box::new(BSTNode::new(value))),
            }
        } else {
            match self.right {
                Some(ref mut right) => right.insert(value),
                None => self.right = Some(Box::new(BSTNode::new(value))),
            }
        }
    }
}
Prints:
code:
BSTNode { value: 5, left: None, right: None }
BSTNode { value: 5, left: None, right: Some(BSTNode { value: 7, left: None, right: None }) }
BSTNode { value: 5, left: Some(BSTNode { value: 2, left: None, right: None }), right: Some(BSTNode { value: 7, left: None, right: None }) }
BSTNode { value: 5, left: Some(BSTNode { value: 2, left: Some(BSTNode { value: 1, left: None, right: None }), right: Some(BSTNode { value: 3, left: None, right: Some(BSTNode { value: 4, left: None, right: None }) }) }), right: Some(BSTNode { value: 7, left: Some(BSTNode { value: 6, left: None, right: None }), right: Some(BSTNode { value: 8, left: None, right: None }) }) }
Which looks right by my checking. I THINK the problem was when you do (self.value > value, self.left, self.right), you implicitly create a new Tuple which borrows self.left and self.right, so you can't use them in your match arms.

Sounds good to me, thanks.

Linear Zoetrope
Nov 28, 2011

A hero must cook
Also, I think the more "Rustic" way is to use an enumerated type instead of a faux-null-pointer option

code:
enum BSTNode {
    Node{left: Box<BSTNode>, right: Box<BSTNode>, value: i64},
    Sentinel,
}
So instead of having the option to have a left or right pointer, you always point to a node which is either a full node or an end marker. So an empty tree is simply a single Sentinel.

leftist heap
Feb 28, 2013

Fun Shoe
I also wouldn't mind seeing more words about lifetimes. The official book is pretty brief about them. Like, both of these work:

code:
#[derive(Debug)]
struct Butt<'a> {
    fart: &'a i32,
    poop: &'a str
}

fn main() {
    let dilz = &32;
    let dong = "balls";
    
    let rear end = Butt{fart: dilz, poop: dong};
    
    println!("My butt: {:?}", rear end);
}
code:
#[derive(Debug)]
struct Butt<'a, 'b> {
    fart: &'a i32,
    poop: &'b str
}

fn main() {
    let dilz = &32;
    let dong = "balls";
    
    let rear end = Butt{fart: dilz, poop: dong};
    
    println!("My butt: {:?}", rear end);
}
What the heck is the difference? Would you ever actually need more than one explicit lifetime for a struct?

Vanadium
Jan 8, 2005

Jsor posted:

Also, I think the more "Rustic" way is to use an enumerated type instead of a faux-null-pointer option

code:
enum BSTNode {
    Node{left: Box<BSTNode>, right: Box<BSTNode>, value: i64},
    Sentinel,
}
So instead of having the option to have a left or right pointer, you always point to a node which is either a full node or an end marker. So an empty tree is simply a single Sentinel.

I don't think there's anything wrong with Option<Box<...>>. It's fairly common and compiles down to a potentially-null pointer, and it saves you the allocations.

Sweeper posted:

I'm basically know nothing about rust, but is there any way to "hide" mutability of a struct?

[...]

How do I not pass '&mut self' to the add function, and keep it as &self? I don't want to declare every object as mutable because a map it contains is mutable. I'd like to hide that implementation detail from the consumer...

Also is there any long winded explanation of lifetimes, I'm an idiot and need more words

Jabor posted:

If you're doing something that modifies your object, you're going to need it to be mutable. This is by design. Having a function that modifies your object out from underneath you despite only taking a read borrow would defeat the entire purpose of the borrow checking and blow all of those safety guarantees out of the water.

Whether a function changes an object isn't an "implementation detail" to be hidden away, it's an inherent part of the contract of that function.

There's a lot of head-wrapping-around to be done with Rust in terms of how it straight-up doesn't let you structure some programs like it'd be the right way in millions of other languages. People on irc tend to scold me when I'm all "but that makes everything ugly and terrible and now I need to pass my state around explicitly like some sort of caveperson", and somehow it never seems to be a problem for all those clever things people do in Rust but I don't really get it.

That said you can use RefCell to move the safety guarantees to dynamic checks instead, that should work here.


rrrrrrrrrrrt posted:

What the heck is the difference? Would you ever actually need more than one explicit lifetime for a struct?

I think in both cases the struct itself is effectively restricted to the intersection of the two lifetimes, and I think it's fairly uncommon to have two lifetime parameters on a single type. But if you want to get one of the references out of the struct again, there's a difference in whether you've coerced both of them to the same intersectional lifetime. Your example isn't too helpful there because your string literals have static lifetime either way, so let's assume a Butt with two integer reference fields instead, then the following would only work with the Butt with separate lifetimes:

code:
fn main() {
    let dilz = 32;
    let p = {
        let dong = 42;

        let rear end = Butt{fart: &dilz, poop: &dong};

        rear end.fart
    };

    println!("My dilz: {:?}", *p);
}

Vanadium fucked around with this message at 09:16 on Jun 20, 2015

Deus Rex
Mar 5, 2005

Vanadium posted:

Do they have a commonly used quickcheck yet?

Yes. https://github.com/BurntSushi/quickcheck

Vanadium
Jan 8, 2005

quote:

Rust 1.1 stable provides a 32% improvement in compilation time over Rust 1.0 (as measured by bootstrapping).

quote:

Benchmark compilations are showing an additional 30% improvement from 1.1 stable to 1.2 beta

I was fairly excited about this like an hour and a half ago when I started building rust from source, not so much now :(

VikingofRock
Aug 24, 2008




So has anyone gotten rust-crypto working recently? A few months ago I was doing the matasano cryptography challenges in Rust, and I wanted to return to it, but the build for rust-crypto is failing. If no one has gotten it to work, does anyone know of any good alternatives? Nevermind, I was mistaken--I hadn't updated my Cargo.lock file. It seems to build just fine on 1.1 and 1.3 nightly.

VikingofRock fucked around with this message at 09:20 on Jul 3, 2015

Linear Zoetrope
Nov 28, 2011

A hero must cook
Can somebody please help me figure out how to do a tree traversal in a loop rather than recursively? The recursive version is blowing up my stack.

The recursive code is essentially:

code:
fn traversal(&mut self, world &mut T) -> Reward {
    if world.is_terminal() {
        return 0.0;
    }

    let action = self.choose_action(world);
    let reward,state = world.act(action);
    
    // Find a child matching that state, or generate a new child
    // this is returned as an &mut MyNodeType
    let next = self.act(state);

    let cum_reward = reward + next.traversal(world);

    self.total_reward[action] = self.total_reward[action] + cum_reward;

    cum_reward
}
This is wrapped in something like:

code:
fn search(world: &mut T, num_trajectories: usize) -> Action {
    let mut root = MyNodeType::new();

    for _ in 0..num_trajectories {
        root.traversal(world);
        world.reset();
    }

    root.select_best_action();
}
My best attempts to loopify this have ended in failure:

code:
fn search(world: &mut T, num_trajectories: usize) -> Action {
    let mut root = MyNodeType::new();

    for _ in 0..num_trajectories {
        let tree = &mut root;
        while !world.is_terminal() {
            let action = tree.choose_action(world);
            let reward,state = world.act(action);
            
            tree = tree.act(state);

            // ... stuck now ...
        }
        world.reset();
        tree = root;
    }

    root.select_best_action();
}
When I try to reassign tree it claims that the borrow lasts until the end of the OUTER loop, so I can't rebind it. And even if I could, I have no idea how to do the post-evaluation of the reward if I could get that far. That would be easy in not-Rust due to laxer aliasing rules (parent pointers, maintain a stack of nodes, whatever), but the borrow checker hates me.

Specifically, it says the problem line is a mutable borrow at the line I call tree.act, which is where it borrows the tree's child out of the node's state->child hash map.

Any ideas? I can't do this recursively because unfortunately it overflows the stack due to the depth of the state space. (I'm running monte-carlo tree search on Space Invaders). I can depth limit it, of course, but even if I do that I'll be able to go deeper if I can unroll this.

Linear Zoetrope
Nov 28, 2011

A hero must cook
It turns out the answer was "use Rc<RefCell<blah>>". That was a fun, if somewhat frustrating, adventure. I eventually went back to the recursive code because it turns out the iterative code had almost no benefit -- the stack overflows at pretty much the same point whether I'm using a homebrewed stack or a recursive one, which I definitely didn't expect!

Flashing Twelve
Mar 20, 2007

Jsor posted:

It turns out the answer was "use Rc<RefCell<blah>>". That was a fun, if somewhat frustrating, adventure. I eventually went back to the recursive code because it turns out the iterative code had almost no benefit -- the stack overflows at pretty much the same point whether I'm using a homebrewed stack or a recursive one, which I definitely didn't expect!

Yeah, the shittiest part of learning Rust is hammering nails into your dick trying to write data structure stuff. It's trivial in other languages, but writing them in (safe) Rust requires a decent understanding of its complex memory model, so it's a pretty bad place to start off. Rc and RefCell are usually enough to cover the gaps the borrow checker can't handle if you're cool with the overhead associated with them. If you're not, or you have a situation that's difficult to solve in safe Rust (doubly-linked list is one), don't be afraid to drop to unsafe{} . The standard library (which is written in Rust) uses it extensively.

VikingofRock
Aug 24, 2008




Speaking of unsafe Rust, there's a new Book in progress which covers it extensively.

Bongo Bill
Jan 17, 2012

unsafe {} doesn't mean the code within is not safe; rather, it means that the memory safety of the block is promised by the programmer, instead of the compiler. The programmer might be wrong, of course. If you are trying to do something that you know is fine, but the compiler isn't smart enough to prove, that's exactly when you should be using unsafe {}. But it's probably wiser to implement it in such a way that the compiler doesn't need to trust you, wherever possible.

Linear Zoetrope
Nov 28, 2011

A hero must cook

Bongo Bill posted:

unsafe {} doesn't mean the code within is not safe; rather, it means that the memory safety of the block is promised by the programmer, instead of the compiler. The programmer might be wrong, of course. If you are trying to do something that you know is fine, but the compiler isn't smart enough to prove, that's exactly when you should be using unsafe {}. But it's probably wiser to implement it in such a way that the compiler doesn't need to trust you, wherever possible.

Hmm, that's an interesting way to look at it. The language is essentially a constructivist proof in terms of safety, in which parts of the program have two possibilities as far as the compiler is concerned: safe or unproven. When the borrow checker fails something, it's because it can't prove it's safe (rather than proving it unsafe), and the unsafe block tells it that its unprovability is okay.

I'd avoided unsafe except for FFI code, but thinking of it that way makes it a bit more palatable to use it when I'm sure something is safe.

Though I would imagine that unsafe also prevents it from passing noalias metadata to LLVM in some cases (though the code may still likely be faster than Rc<Refcell<T>>).

Jo
Jan 24, 2005

:allears:
Soiled Meat
I've been dicking around with Rust 1.0 recently and started fiddling with some Project Euler exercises. One thing that has been biting me is this: at times I'd like to use a variable x as a usize and other times as u64. In this case, I have one function which builds a sieve for the sieve of aristophanes (Vec requiring a usize) and another which does a multiplication into this requiring a u64. Is there an idiomatic way in Rust to use a numeric type, or am I attacking this from entirely the wrong angle?

Linear Zoetrope
Nov 28, 2011

A hero must cook

Jo posted:

I've been dicking around with Rust 1.0 recently and started fiddling with some Project Euler exercises. One thing that has been biting me is this: at times I'd like to use a variable x as a usize and other times as u64. In this case, I have one function which builds a sieve for the sieve of aristophanes (Vec requiring a usize) and another which does a multiplication into this requiring a u64. Is there an idiomatic way in Rust to use a numeric type, or am I attacking this from entirely the wrong angle?

You can do a type conversion with (x as usize), if you're on a 64-bit machine this is probably a no-op at runtime. Though it sounds like your multiplication function should probably be generic over the Mul trait.

Unless you're multiplying by a constant. At the moment, unfortunately there's no good way to do generic arithmetic with any constants.

Jo
Jan 24, 2005

:allears:
Soiled Meat

Jsor posted:

You can do a type conversion with (x as usize), if you're on a 64-bit machine this is probably a no-op at runtime. Though it sounds like your multiplication function should probably be generic over the Mul trait.

Unless you're multiplying by a constant. At the moment, unfortunately there's no good way to do generic arithmetic with any constants.

All constants. I have two functions, one which finds the prime factors of a number (u64), and another which builds a sieve (which I'd use u64 for, but the array constructor requires usize). I'll see if I can copy my code over to this machine to share. I feel a bit bad using 'as usize' all over the place, but if there's no better way, I'll deal with it.

Linear Zoetrope
Nov 28, 2011

A hero must cook
Just throw type conversions around. IME it's pretty common, at least until associated constants become a thing. That or refactor the prime factor code to take a usize.

Tarion
Dec 1, 2014
1.5 is out and 'cargo install' seems pretty cool.

VikingofRock
Aug 24, 2008




Tarion posted:

1.5 is out and 'cargo install' seems pretty cool.

Agreed. It seems like Rust tooling is really taking off, which is very exciting to me.

Linear Zoetrope
Nov 28, 2011

A hero must cook

VikingofRock posted:

Agreed. It seems like Rust tooling is really taking off, which is very exciting to me.

Rust's runtime debugging really needs some work, though. If you have an erroneous `unwrap` you helpfully get the line number of the source code for Option it calls panic! on rather than the actual part of your code. This would be fine if RUST_BACKTRACE wasn't utterly useless on non-Linux systems, on my Windows machine it helpfully prints:

code:
thread '<main>' panicked at 'panic', main.rs:2
stack backtrace:
   0:           0x43bc4b - <unknown>
   1:           0x443eae - <unknown>
   2:           0x40555c - <unknown>
   3:           0x401592 - <unknown>
   4:           0x40151f - <unknown>
   5:           0x443948 - <unknown>
   6:           0x42ea11 - <unknown>
   7:           0x44384d - <unknown>
   8:           0x4016ea - <unknown>
   9:           0x4013b4 - <unknown>
  10:           0x4014e7 - <unknown>
  11:     0x7ffa905a2d91 - <unknown>
This is just a "hello, panic!" program, basically. Panics first thing in main.

Gee, thanks, Rust, I learned so much. It's a good thing 98% of your Rust bugs the compiler catches, and 1.5% are logic errors that result in incorrect computations. Runtime panics happen so rarely this is at least tolerable. I can mostly get around it by always using expect instead of unwrap and making sure each possible panic has a unique error message.

Tarion
Dec 1, 2014

Jsor posted:

Gee, thanks, Rust, I learned so much. It's a good thing 98% of your Rust bugs the compiler catches, and 1.5% are logic errors that result in incorrect computations. Runtime panics happen so rarely this is at least tolerable. I can mostly get around it by always using expect instead of unwrap and making sure each possible panic has a unique error message.

You're not really supposed to use unwrap in 'production' code anyways.

Adbot
ADBOT LOVES YOU

Flashing Twelve
Mar 20, 2007

Jsor posted:

Rust's runtime debugging really needs some work, though. If you have an erroneous `unwrap` you helpfully get the line number of the source code for Option it calls panic! on rather than the actual part of your code. This would be fine if RUST_BACKTRACE wasn't utterly useless on non-Linux systems, on my Windows machine it helpfully prints:

code:
thread '<main>' panicked at 'panic', main.rs:2
stack backtrace:
   0:           0x43bc4b - <unknown>
   1:           0x443eae - <unknown>
   2:           0x40555c - <unknown>
   3:           0x401592 - <unknown>
   4:           0x40151f - <unknown>
   5:           0x443948 - <unknown>
   6:           0x42ea11 - <unknown>
   7:           0x44384d - <unknown>
   8:           0x4016ea - <unknown>
   9:           0x4013b4 - <unknown>
  10:           0x4014e7 - <unknown>
  11:     0x7ffa905a2d91 - <unknown>
This is just a "hello, panic!" program, basically. Panics first thing in main.

Gee, thanks, Rust, I learned so much. It's a good thing 98% of your Rust bugs the compiler catches, and 1.5% are logic errors that result in incorrect computations. Runtime panics happen so rarely this is at least tolerable. I can mostly get around it by always using expect instead of unwrap and making sure each possible panic has a unique error message.

Yeah Windows debugger stack traces were working fine a little while back but ever since I upgraded to 1.4 beta and on it's been broken. Bit of a pain, unwrap isn't ideal and all but it's great for testing/prototyping. Tooling is definitely something Rust is lacking in at the moment.

One of the Mozilla Rust guys lists his predictions for Rust in 2016. Better tooling is high up on that. Personally Visual Rust fully fleshed out would be a breaking point for me, decent IDE support and VS's debugger would be a multiplier on my productivity for sure.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply