Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Getting acquainted with Rust's mio (hoverbear.org)
36 points by mseri on March 4, 2015 | hide | past | favorite | 23 comments


Out of curiosity, Rust was first built on libuv, then libuv was removed, now mio looks like an API very similar to libuv, but not using libuv. What were the decisions behind this and why is it better than not using an existing lib that should be easy to plug into Rust via FFI since it is small and in C?


There's a long history here. An abridged and slightly biased / not complete story follows.

In the beginning, Rust had only green threads. This was because concurrency was deemed important, and everybody knows green threads are where it's at. (totally not sarcasm. Totally.)

Eventually, it was decided that a systems language without systems threads is... strange. So we needed to add them. Why not add choice? Since the interfaces could be the same, why not abstract over them, and you could just choose which one you wanted?

At the same time, the problems with green threads by default were becoming issues. Segmented stacks cause slow C interop. You need a runtime to manage them, etc.

Furthermore, the overall abstraction was causing an unacceptable cost. The green threads weren't very green. Plus, with the need to actually release someday looming, decisions needed to be made regarding tradeoffs. And since Rust is supposed to be a systems language, having 1:1 threads and basically no runtime makes more sense than N:M threads and a runtime. So libgreen was removed, the interface was re-done to be 1:1 thread centric, and Servo got mad. That's another story.

That doesn't mean that green threads are evil. Remember, I/O isn't a language thing, really, it's a library thing, in a language as low-level as Rust. In fact, that's one of the reasons green threads could be removed: libraries like mio could provide the benefits, without the problems that were being caused. Servo might also write a green threading library, with a different set of tradeoffs from mio's implementation.

Anyway, this is my pre-coffee explanation of the history. I'm being a bit silly, so please don't read into any particular bit of language here, that's just the high-level story.


Great post. I didn't check mio before but after reading the post I can probably jump start.


I'm sure event loops have their uses in all languages, but I'm not sure why the author rubbishes Python and JS, citing callback hell, and then writes an example that uses callbacks.

Anyway, the article's introduced me to consensus algorithms, so thanks for that.


Yes, the example uses callbacks, sure, but the point was intended to be that not everything is callback based, like in Node, you can use it where it's appropriate.


You sure it wasn't just an excuse to bash dynamically typed languages? ;)

In any case, I'll be interested in seeing how it ends up getting used. It's nice to have it available.


You lost me there. What's this about?


An IO abstraction in Rust.


[flagged]


Trollish troll is trolling.

Rust has a myriad of ways to handle errors, and unwrap is the most blunt of those instruments as it explicitly converts handleable errors into panics.

Alternatives such as try!, unwrap_or(), and many others, should be your preferred options. I try to only use unwrap() in throwaway code and usually only in main functions.

The one thing rust doesn't let you do (at least without warnings), is to have unhandled errors.

Being forced to explicitly handle error conditions is a huge net win for any production code.


> The one thing rust doesn't let you do (at least without warnings), is to have unhandled errors.

Sounds a bit like Java's checked exceptions, largely regarded as a failed experiment. What makes Rust's version better?


Alternately, it's like Haskell's monads, largely regarded as a workable solution.

I think the key difference between checked exceptions and Rust's monadic error handling is that it's very easy to just panic if you don't care about recovering from the error. In Java you have to write "try { ... } catch (IOException e) { throw new RuntimeException(e); }", which is very verbose, and it's a lot less code to just ignore the exception. In Rust it's just ".unwrap()".


Monads have become a borderline buzzword these days. You're obviously the expert on Rust here, but it feels like it would be sufficient to just call it errors-as-values.


That there are no unchecked exceptions.


How many other ways to handle errors are there besides the three you mentioned? Why not just default to panic then if you are going to have to type unwrap everywhere? Does typing that all over the place prevent you from having errors in production?

The whole thing is asinine. Its the worst part of programmer culture.


You can write unwrap in production, if you know that the error isn't supposed to happen. But Rust's error handling forces you to think about errors and how to handle them, by design. Rust's way is also much more efficient at runtime, because using stack unwinding to recover from every error would be slow in the cases where errors are an expected and normal part of operation.


Question 1: because it's the wrong default for robust code.

Question 2: no, you don't use unwrap in production.


Jesus. What would the 'correct' MIO production code look like without unwraps? Or is that a PhD research project, 'correctly' implementing this page of code for 'production'?


If this were not happening in main(), then the following would be one way of handling the errors.

  fn foo() -> Result<(),Error> {
      // Create an event loop
      let mut event_loop = try!(EventLoop::<(), u64>::new());
      let sender = event_loop.channel();
      for i in 0.. 5 {
          try!(sender.send(i));
      }
      // Start it
      try!(event_loop.run(&mut BearHandler(0));
  }


You can always use `map`, `and` and `and_then`.


`.unwrap()` is used in these examples to avoid having to include code to handle errors. I'd much rather see `.unwrap()` then NullPointerException popping up whereever.

In "real" Rust code we have several ways of dealing with possible errors and "None" results.

`.to_string()` tells the compiler to use a `String` which owns it's memory instead of a `&str` which is doesn't own it's...

Oh wait, reading your comment you're trolling.


Give it a chance to grow, and give yourself a chance to learn it. You're talking about a brand new language implementing a memory management system largely untried in production code (although C++ has it now).

The language will be refined as its strengths and weaknesses are exposed.


C++ has nothing of the sort.


I'm referring to unique_ptr, introduced in C++11.

http://www.stroustrup.com/C++11FAQ.html#std-unique_ptr




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: