Live data from Hacker News

100 days with Rust: a series of brick walls

brandur.org

191–200 of 323 posts

Re: 100 days with Rust: a series of brick walls

#191

Earlier quoted context omitted.

I recently wrote a few projects in Rust (C/C++/Go/JavaScript/Java/Python as background), and very much like the language. My 2 cents from my endeavors with Rust I felt like all type errors are backwards. That is, "got" was the target you are giving your type to, not the type that you are passing. This may only happen in some cases, but I just started tuning the content of those errors out and instead adjusted randoml…

Oh, and added thing that bugged me a lot: The error part of Result . During my short time of coding Rust (I'll get back to it later), I never really found a way to ergonomically handle errors. I find it really awkward that the error is a concrete type, making it so that you must convert all errors to "rethrow". Go's error interface, and even exception inheritance seems to have lower friction than this.

I'm quite fond of error-chain (https://github.com/rust-lang-nursery/error-chain), which helps mitigate it somewhat. You can do things like:

    use error::{Error, ErrorKind, Result, ResultExt};
    
    fn some_func(v: &str) -> Result {
        v.parse::().chain_err(|| ErrorKind::ParseIntError)
    }
The purpose of `chain_err` here is to add on top of the previous error, to explain what you were trying to do, instead of passing up the previous error (in this case, `std::num::ParseIntError`).

If you don't like that, you can do something like this:

    use std::boxed::Box;
    use std::error::Error;

    fn some_func(v: &str) -> Result> {
        v.parse::().map_err(|e| Box::new(e))
    }
But then you'd have to box every error.

Re: 100 days with Rust: a series of brick walls

#192
post #156

Earlier quoted context omitted.

> Ah, it sounds like you're using traits as types directly, which is very much discouraged by Rust (especially in conjunction with taking references to those traits). What the language really prefers for you to do is to use traits as bounds on generic types Can you write an example?

Sure thing. [Preemptive postscript: damn this got long. TL;DR don't use trait objects, just use generics. You'll thank me.] Here's the setup: we have several different types, and those types implement the same trait (think of it like an interface from other languages). // Define two different types struct Chihuahua; struct GreatDane; // Define a trait with a method trait Bark { fn bark(&self); } // Implement that met…

There's a third way you didn't mention, and which replaces most uses of trait objects in practice: use an enum.

Re: 100 days with Rust: a series of brick walls

#193

Earlier quoted context omitted.

Docs team lead here. Specific feedback on improving the output of the docs is absolutely, 100% welcome. Without knowing what "it" is, I can't say if we're "denying that it is a problem." We are constantly tweaking the layout of stuff, and have some larger plans on the way as well.

For the languages I've used (Node and Python), I'm just comparing the ease of finding documentation on the language homepage. A typical flow is: Homepage > docs > reference/api Node is very straightforward: https://nodejs.org/api/index.html Python has a library reference and a language reference: https://docs.python.org/3/library/index.html https://docs.python.org/3/reference/index.html All 3 of these pages are blata…

Thank you! It's a bit late here, so I'm going to bookmark this and get back to it when I can fully appreciate all the detail <3

Re: 100 days with Rust: a series of brick walls

#194
post #169

Earlier quoted context omitted.

I can see where the author comes from. I've been working with ^W^W fighting against Tokio this week, and the error messages are horrible. Representative example: error[E0271]: type mismatch resolving ` + std::marker::Send>, [closure@src/server/mod.rs:59:18: 59:74]>, [closure@src/server/mod.rs:60:19: 69:10 next_connection_id:_], std::result::Result >, futures::MapErr , [closure@src/server/mod.rs:74:18: 74:74]>>, std::…

Yeah, i have recently finished a tokio based server. Working with future combinators is very frustrating. I accidentally captured a variable in a closure(should be cloned and moved), and it didn't tell me where it happened, just an error saying requires 'static lifetime for the variable.

The new async/await stuff will help a lot with this; it'll enable borrowing across futures, which will remove this requirement and make things a lot simpler.

Re: 100 days with Rust: a series of brick walls

#195
post #143

Earlier quoted context omitted.

Yes, slower than modern GC, but predictable and deterministic. Note that the parent comment never claimed it was faster, just that it avoids 'stop the world' which can be a problem in realtime contexts (e.g. games, audio).

Reference counting isn't inherently more predictable than tracing garbage collection. Take the example where your thread is the last one to deref a gigantic object graph. You're stuck holding the bag on traversing the entire graph and destructing it all at once, when a tracing gc could do it piecemeal (and on a dedicated background thread, instead of on your real worker threads).

If objects that hit zero refs have their reference pushed into the queue of a dedicated GC thread, is that not still called RC, or is that called something else?

Re: 100 days with Rust: a series of brick walls

#196
post #110

Earlier quoted context omitted.

> My code was littered with .as_str() and .to_string(). PSA: If you have a variable that's a String, you can easily pass it to anything that expects a &str just by taking a reference to it: fn i_take_a_str(x: &str) {} let i_am_a_string = "foo".to_string(); i_take_a_str(&i_am_a_string); Every variable of type &str is just a reference to a string whose memory lives somewhere else. In the case of string literals, that m…

Ah, I found that out later but had forgotten all about it. :) I don't remember how I found out, but it seemed oddly magical until I just now read the docs: String implements Deref . Makes more sense now. I still had a bunch of to_strings()'s, though, as things tended to take String whenever I had &str's. I found this to be a very unexpected nuisance. EDIT: Maybe I needed as_str() as the & trick doesn't work if the ta…

FWIW, this is why we go over this stuff in the book now; lots of people struggle with it, it's not just you.

And yeah, Deref doesn't kick in everywhere, so you may need the .as_str() in those situations. It should be the extreme minority case, generally. Same with .to_string(), though moreso. Most stuff should take &str, not String.

Re: 100 days with Rust: a series of brick walls

#197

Earlier quoted context omitted.

I recently wrote a few projects in Rust (C/C++/Go/JavaScript/Java/Python as background), and very much like the language. My 2 cents from my endeavors with Rust I felt like all type errors are backwards. That is, "got" was the target you are giving your type to, not the type that you are passing. This may only happen in some cases, but I just started tuning the content of those errors out and instead adjusted randoml…

Oh, and added thing that bugged me a lot: The error part of Result . During my short time of coding Rust (I'll get back to it later), I never really found a way to ergonomically handle errors. I find it really awkward that the error is a concrete type, making it so that you must convert all errors to "rethrow". Go's error interface, and even exception inheritance seems to have lower friction than this.

? should help a lot with this, but libraries like error-chain, or the newer (and, IMO much better) failure can help even more.

Re: 100 days with Rust: a series of brick walls

#198
post #72

Earlier quoted context omitted.

Two things jump out at me: 1. Automatic reference counting is a really good alternative to GC. It takes a little bit more book-keeping, but the performance characteristics are predictable since allocations/frees are handled along the way. Many GC implementations require execution to be halted while the reference graph is traced, which makes it a non-starter for applications trying to deliver predictable real-time per…

if something is hard to do in Rust it's probably an anti-pattern with respect to memory performance or safety. Oh? Tell me, how many lines of Rust does this take you? struct Task { struct Task *next; struct Task *prev; struct TaskRegs regs; //other shit here } Or are doubly-linked lists antipatterns now?

  struct Task {
      next: *mut Task,
      prev: *mut Task,
      regs: TaskRegs,
      // other shit here
  }
is the direct translation.

> Or are doubly-linked lists antipatterns now?

They're often not what you want, yes. But if you are in that situation, in the worst case you're in the same place as C, and you can write the Rust the same way if you'd like.

Re: 100 days with Rust: a series of brick walls

#199

Earlier quoted context omitted.

> It's important to note that in C++ you can easily run into problems with what you're describing: structs (objects) with different sizes being put into a vector. Baloney. In C++ vector or vector accomplish this task without any problems whatsoever.

And you can do the same in Rust with Box . What Rust doesn't have is the object slicing gotcha, which is probably a language design mistake in C++.

That gotcha is yet another flaw inherited from copy-paste compatibility with C.

structs being classes with public access by default, with default assignment operator behaving the same way as C code would expect.

Re: 100 days with Rust: a series of brick walls

#200

Earlier quoted context omitted.

That's because the trait section only shows what traits a type implements. If you want to see how to use a trait just click that trait's name for the trait specific documentation.

Sometime I don't know what trait I need, but I do know what kind of operation I want. In documentation such as Python's, I can "ctrl + F" for word similar to what I want to do and I usually find what I need. In rust, that textual description is usually hidden on the trait's page. This is probably more frustrating to beginners who don't know what most of the basic traits are. In general though, the standard library is…

The built-in Rustdoc search isn't perfect, but it should search the textual description for you. It might only search the first line? I should dig into that code again...
Post reply on HN