Live data from Hacker News

Implications of Rewriting a Browser Component in Rust

hacks.mozilla.org

131–140 of 279 posts

Re: Implications of Rewriting a Browser Component in Rust

#131

Earlier quoted context omitted.

Honestly, I wish a few different major languages would get together and start developing system ABIs that move beyond C as the interchange language.

But what would you put in such an ABI beyond what's in the C ABI? Beyond basic data types, struct defintions, and function definitions, languages begin to wildly diverge almost immediately.

Multiple return values. Ownership annotations. SIMD type support. String charset information.

More challenging would be to include stuff like allocation management (how to free a pointer when it's done), GC integration, function boxing, iterator/generator support. Vtables and cross-language inheritance is interesting but difficult.

One point of clarity: this would be an FFI ABI, not necessarily expecting that most datatypes would be laid out according to the ABI.

Re: Implications of Rewriting a Browser Component in Rust

#132

Earlier quoted context omitted.

>could you please tell me what kind of official formal proof tools exist for Rust that makes it predictable? I feel like you aren't really asking a question, that your intent was really to lecture someone, but in case you really are: * a borrow checker * option types So OCaml would catch a similar set of obvious errors, though Rust would also catch all data races at compile time, as the borrow checker does that as we…

No, I was really curious. My bad if it looked like I was trying to lecture. I do not think that I have the necessary knowledge in this topic to do that. :) > a borrow checker What exactly do you mean? How does it differ from any other language's type system? > would also catch all data races at compile time In Ada/SPARK, you can formally verify tasks, too. Please take a look at https://docs.adacore.com/spark2014-docs…

> What exactly do you mean? How does it differ from any other language's type system?

If you're familiar with affine types, this is basically what Rust's borrow checker implements.

If you're not familiar, it's a bit complicated to summarize on Hacker News. You should try it out, because it lets you guarantee statically entire classes of properties that non-academic languages struggle with.

> In Ada/SPARK, you can formally verify tasks, too. Please take a look at https://docs.adacore.com/spark2014-docs/html/ug/en/source/co.... if you have some time!

I'm not an expert in Ada, but yes, that's pretty similar to some of the properties Rust will let you check out of the box.

edit My memory of Ada was incorrect.

Re: Implications of Rewriting a Browser Component in Rust

#133

Earlier quoted context omitted.

I was responding to the issue I quoted, which really is just a matter of using a programming language with static typing. :) > some of which aren’t solved by other languages You only mentioned null pointers, so I will go with that. In Ada, you can have access types (pointers) that are guaranteed to not be null, and accessibility rules of Ada prevent dangling references to declared objects or data that no longer exist…

Ada is awesome, and if compiler writers had been more timely it might have taken hold. Rust solves the same problems without a runtime, and about 3 times the performance. Granted it looks like c++ and ocaml made a particularly ugly child.

Which problems are you referring to?

You can do everything that has been mentioned without Ada's RTS, you can also disable all run-time checks. You can use static analysis tools (there are many, and available for free), for example, you can formally verify the correctness of the program, no run-time checks required.

Re: Implications of Rewriting a Browser Component in Rust

#134

Earlier quoted context omitted.

>could you please tell me what kind of official formal proof tools exist for Rust that makes it predictable? I feel like you aren't really asking a question, that your intent was really to lecture someone, but in case you really are: * a borrow checker * option types So OCaml would catch a similar set of obvious errors, though Rust would also catch all data races at compile time, as the borrow checker does that as we…

No, I was really curious. My bad if it looked like I was trying to lecture. I do not think that I have the necessary knowledge in this topic to do that. :) > a borrow checker What exactly do you mean? How does it differ from any other language's type system? > would also catch all data races at compile time In Ada/SPARK, you can formally verify tasks, too. Please take a look at https://docs.adacore.com/spark2014-docs…

> > a borrow checker

> What exactly do you mean? How does it differ from any other language's type system?

Part of rust's type system is sub-structural: by default, Rust's types are affine, which means you can only use them once (at most, not exactly).

Now this is not super convenient to use and could have efficiency issues (e.g. any time you want to check a value in a structure you'd have to return the structure so the caller can get it back), so to complement this you can borrow (create a reference). The borrow checker is the bit which checks that borrows satisfy a bunch of safety rules, mostly that a borrow can't outlive its source, and that you can have a single mutable borrow or any number of immutable borrows concurrently.

The borrow checker provides for memory-safe pointers to or into a structure you're not the owner of, with no runtime cost.

Re: Implications of Rewriting a Browser Component in Rust

#135

Earlier quoted context omitted.

>could you please tell me what kind of official formal proof tools exist for Rust that makes it predictable? I feel like you aren't really asking a question, that your intent was really to lecture someone, but in case you really are: * a borrow checker * option types So OCaml would catch a similar set of obvious errors, though Rust would also catch all data races at compile time, as the borrow checker does that as we…

No, I was really curious. My bad if it looked like I was trying to lecture. I do not think that I have the necessary knowledge in this topic to do that. :) > a borrow checker What exactly do you mean? How does it differ from any other language's type system? > would also catch all data races at compile time In Ada/SPARK, you can formally verify tasks, too. Please take a look at https://docs.adacore.com/spark2014-docs…

[deleted]

Re: Implications of Rewriting a Browser Component in Rust

#136
post #55
post #4

It's nice to see a balanced, real world, case study including 'these things are fixed by Rust', 'these are problems that don't occur in idiomatic Rust', and 'these are problems that Rust can't help you with'. I'm a big fan of Rust, but the one sided 'Rust makes all the problems go away' articles don't provide any value.

Overall, it did a decent job of being balanced, but I don’t buy the memory overflow example at all. For one thing, idiomatic C++ bounds checks by default. You need to use at(). If you don’t like typing at(), you can implement an array type that always bounds checks fairly easily. On that note, the vulnerable c++ code should be using accessors, not indexing to access the oddly packed and laid out array. Even the fixed…

> You need to use at()

That's not "by default". std::array_view still hasn't landed so I can't even wrap ptr+size s provided by third party libraries or across standardized C ABIs without going beyond the standard library (really not by default now)... and I believe I have yet to see a single solitary use of at() in a production C++ codebase. Some "default".

For code where overflows are expected, C++ exceptions are way too heavyweight and some other kind of "attempt dereferencing" pattern is used (if only checking the index manually before invoking operator[]).

For code where overflows are unexpected, uncatchable assert-style checks are used.

Re: Implications of Rewriting a Browser Component in Rust

#137

Earlier quoted context omitted.

I was responding to the issue I quoted, which really is just a matter of using a programming language with static typing. :) > some of which aren’t solved by other languages You only mentioned null pointers, so I will go with that. In Ada, you can have access types (pointers) that are guaranteed to not be null, and accessibility rules of Ada prevent dangling references to declared objects or data that no longer exist…

Ada is awesome, and if compiler writers had been more timely it might have taken hold. Rust solves the same problems without a runtime, and about 3 times the performance. Granted it looks like c++ and ocaml made a particularly ugly child.

>> [...] solves the same problems without a runtime, and about 3 times the performance.

I think you should look more into Ada. The only "runtime" is for the exception handling and bounds checking, both of which can be turned off if needed.

And I don't know where you got that "3 times" figure from? Do you have an example you are referring to?

Re: Implications of Rewriting a Browser Component in Rust

#138
post #82

Earlier quoted context omitted.

This comment is confusing two completely separate concepts: zero cost abstractions and run time bounds checks. Rust does provide zero cost abstractions: if you do something explicitly/manually instead of using the abstraction you get the same generated code. If you want to combine the two concepts, I guess you could go for an example like this: if index >= vec.len() { panic!("out of bounds"); } let value = unsafe { v…

What's an example of a language where the second would be more expensive than the first?

For that specific example it's hard to be expensive but here's a loop from one of my crates that compiles down to efficient code:

    pub fn decode_12be(buf: &[u8], width: usize, height: usize) -> Vec {
      decode_threaded(width, height, &(|out: &mut [u16], row| {
        let inb = &buf[(row*width*12/8)..];

        for (o, i) in out.chunks_exact_mut(2).zip(inb.chunks_exact(3)) {
          let g1: u16 = i[0] as u16;
          let g2: u16 = i[1] as u16;
          let g3: u16 = i[2] as u16;

          o[0] = (g1 > 4);
          o[1] = ((g2 & 0x0f) 
The "decode_threaded()" call is a function call that passes in a closure with the inner loop to a generic function that is used to multithread a bunch of similar decoders, instead of repeating that code. And the for loop is actually describing what I want (process every 3 bytes into 2 output values) instead of having me manage some iteration variables and have off-by-one bugs. "chunks_exact" and "chunks_exact_mut" are recent additions that allow me to say that I only want to receive exactly 3 bytes and output exactly 2 values, so if the array is improperly sized the extra at the end just gets skipped. This not only matches the intention of this code (I only ever process 2 pixels from 3 bytes and nothing else will work) but also gives the compiler a better way to lift the bounds checks out of the inner loop and make the code significantly faster (by 2x in some decoders).

Now let's see "decode_threaded":

    pub fn decode_threaded(width: usize, height: usize, closure: &F) -> Vec
      where F : Fn(&mut [u16], usize)+Sync {

      let mut out: Vec = alloc_image!(width, height);
      out.par_chunks_mut(width).enumerate().for_each(|(row, line)| {
        closure(line, row);
      });
      out
    }
Besides allocating the image it uses "par_chunks_mut" to make the code threaded. That's a function that's provided by the rayon crate which manages a threadpool and it's scheduling for me. So I'm even using code written by other people, to build something that's apparently deeply nested even though it needs to be fast. And yet after all this indirection and syntax goodies the end result is efficient machine code that matches or is even better than the original C++ code and not the dynamic runtime like behavior of Ruby/Python that you'd expect from such code.

That's what zero cost abstractions are. After memory and data race safety I think rust shines because it gives me a lot of the ergonomics of Ruby with the speed of C.

Re: Implications of Rewriting a Browser Component in Rust

#139

Earlier quoted context omitted.

Agree completely. For a bit of my own story, a year+ ago I had the option to write a project in Rust and evaluated it vs Go. Long story short, I tried rust, and it was a massive headache and I failed. We used Go (as I had been for ~4 years). Fast forward to ~2 months ago, a work project dictated tight control over memory which, while possible in Go, had me looking at alternatives. I decided to give Rust another try.…

It’s probably a combination of both things, but “I tried rust, struggled, quit, came back months or years later and now I have no idea why I thought it was so hard” is certainly a recurring pattern we’ve seen. Glad it’s working for you now!

Both type inference and borrow checking have also received a whole bunch of small improvements over the past couple years. Subtle enough that you probably wouldn't notice them except in that the language just takes less effort to use.

If you use Rust 2018 now, non-lexical lifetimes are a bigger recent improvement: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/ow...

Post reply on HN