27 comments

  • toxik an hour ago ago

    Interesting deep dive. Can't say I understand the nuances really, and some of the Rust syntax looks incredibly arcane to me as an outsider.

  • neuroelectron an hour ago ago

    So rust isn't just a clever name.

  • saghm a day ago ago

    Not related to the topic, but seeing this tidbit in the article took me by surprise;

    > PSA: if you don’t see syntax highlighting, disable the 1Password extension.

    This linked to the following discussion that's been ongoing for over a week (with acknowledgement from 1password that they're looking into it but as far as can tell no ETA on the fix or explanation for why it's happening in the first place):

    https://www.1password.community/discussions/developers/1pass...

    I know that browser extensions are in general a pretty terrible ecosystem in terms of security, but am I off-base for thinking this is not a great look for 1password? Maybe I'm just underestimating how hard this is to solve generally, but my expectation would be that it shouldn't be that hard to keep track of which circumstances you're loading entire external scripts to manipulate the DOM and not do it accidentally in places you have no need for it.

    • Chilinot an hour ago ago

      Yea i think this discussion was quite interesting as well. And i can also verify that this issue exists in Zen (firefox based) as well.

  • dmitrygr 2 days ago ago

       For example, before we had something like:
         top: *const FFISafe<WithOffset<&'a u8>>
       We can change that to:
         top: WithOffset<*const FFISafe<&'a u8>>
    
    
    rust, you were meant to replace c++, not join it...
    • Aurornis an hour ago ago

      FYI to non-Rust devs wondering what's going on with this code: Those two abstractions (FFISafe and WithOffset) are not standard Rust abstractions. They're something the author is building within their own library: https://github.com/memorysafety/rav1d/blob/25e5574/src/ffi_s...

      So for all of the complaining about Rust abstractions and syntax in this thread, keep in mind that these particular abstractions that caused this problem are not standard. If you just want to call an extern "C" function you can do so directly in an unsafe block. The article should be read as the author debugging their Rust wrapper types, not as a generic article about calling C functions from Rust.

    • mpyne an hour ago ago

      > rust, you were meant to replace c++, not join it...

      Turns out that not all of the C++ noise people make fun of is due to C++, sometimes the problems you want to solve with Rust or C++ is just hard to express simply to the compiler.

    • saghm a day ago ago

      The point of Rust is ostensibly to provide a safer version of C++-like semantics, not necessarily to avoid the same level of complexity. Especially if you're directly using unsafe code (which is necessary in some cases, like FFI), it's not really clear to me that Rust was "meant" to be doing something wildly different here. The large majority of the code not needing to use unsafe will still be better off even if this type of thing is necessary in some places.

      (To preempt any potential explanations about this: yes, I understand the reference being made with that quote. I just don't think it actually applies here at all)

      • zephen a day ago ago

        This is all well and good, but "zero cost abstractions" implies, well, that you're crawling _up_ the abstraction pyramid, not lost in twisty little side passages.

        • pizza234 21 minutes ago ago

          "Zero cost abstractions" refers to some features of the language that provide functionalities with no runtime cost, e.g. (safe) iterators, not to a presumed simplicity of the whole language. Therefore, this is not mutually exclusive with the fact that certain concepts in Rust require more complexity than their counterpart in other languages (after all, the complexities of the borrow checker don't exist in C).

          In general, and it applies to the referenced article, programming with a high level of control over the implementation is complex, and there's no way around it. This article explains the concept: https://matklad.github.io/2023/01/26/rusts-ugly-syntax.html.

        • saghm a day ago ago

          I've never understood that to mean that every possible abstraction would be zero cost, but that the language itself provides abstractions that are zero cost. I'm not sure how you could avoid having external libraries ever implement an abstraction with a cost. I honestly can't tell from this article alone what library the type `FFISafe` is from, but it's not from std.

          (As an side someone whose spent a lot of time in the ecosystem might be able to infer this is likely a third-party library just from the fact that the capitalization is not in the typical format that official things use; if it were in std, I'd expect it to be FfiSafe, similar to how IoSlice[1], Arc[2], Shl[3], TypeId[4] etc. don't treat separate parts of an abbreviation/acronym/initialism as word breaks).

          [1]: https://doc.rust-lang.org/std/io/struct.IoSlice.html [2]: https://doc.rust-lang.org/std/sync/struct.Arc.html [3]: https://doc.rust-lang.org/std/ops/trait.Shl.html [4]: https://doc.rust-lang.org/std/any/struct.TypeId.html

          • zephen 20 hours ago ago

            > I've never understood that to mean that every possible abstraction would be zero cost, but that the language itself provides abstractions that are zero cost.

            To me, "zero cost abstractions" means that you should use the language, because even the fancy abstractions it provides are free. Which presupposes that the language designers _believe_ that abstractions _and_ performance are both _important_.

            Judging by all the puff pieces on the language, I don't think I'm alone in this belief of what the average Rustacean holds to be true.

            > I'm not sure how you could avoid having external libraries ever implement an abstraction with a cost.

            But the point is that the exact same external library code has a _lower_ cost if called from the non-abstract horror of a language C, and the (partial) fix for that is really ugly looking low-level Rust crap that that took a _long_ time to figure out and is the exact opposite of an abstraction, and the full fix is not even known yet.

            Yes, we all know that abstractions sometimes obscure what is really going on, but the tradeoff is that the code is shorter and prettier, and easier to understand at a higher level. That's... not what is going on here.

            • Aurornis an hour ago ago

              > if called from the non-abstract horror of a language C, and the (partial) fix for that is really ugly looking low-level Rust crap that that took a _long_ time to figure out and is the exact opposite of an abstraction,

              In case it's not clear, the FFISafe abstraction is not a Rust standard library feature. It's a wrapper type that the author created within their library to bypass some compiler warnings:

              https://github.com/memorysafety/rav1d/blob/25e5574/src/ffi_s...

              If you want to call C functions from Rust it's as simple as writing an extern block and then calling the function, though you'll have to put the call in an unsafe block because obviously the Rust compiler can't make safety guarantees across that boundary.

              The Rust docs for extern are concise: https://doc.rust-lang.org/std/keyword.extern.html

            • saghm 20 hours ago ago

              > But the point is that the exact same external library code has a _lower_ cost if called from the non-abstract horror of a language C, and the (partial) fix for that is really ugly looking low-level Rust crap that that took a _long_ time to figure out and is the exact opposite of an abstraction, and the full fix is not even known yet.

              No, it's not the exact same external library. There's an additional Rust library in between that they used, which provides the `FFISafe` type, and that has overhead. This is not a standard Rust library, or even one that I'm able to find within a few minutes of googling despite having used Rust for over a decade. It's not clear to me why you think this is necessarily representative of Rust rather than one specific library; someone could just as easily wrap a C library in another C library in a way that adds overhead, and it would be equally nonsensical to cite that as an argument that C isn't efficient.

              Your argument seems to boil down to "Rust claims to be efficient, but it's possible for someone to write inefficient code, and for me to use that code, so therefore those claims are wrong".

              • zephen 19 hours ago ago

                > No, it's not the exact same external library.

                It uses the exact same assembly language.

                > There's an additional Rust library in between that they used, which provides the `FFISafe` type, and that has overhead.

                Look, I wrote " But the point is that the exact same external library code has a _lower_ cost if called [from C]" and that remains a true statement. It's pretty obvious that I was referring to the shared code, otherwise, it wouldn't have ever been called from C, right?

                The profiler showed that the identical assembly language itself was taking more cycles when called from C.

                > There's an additional Rust library in between that they used, which provides the `FFISafe` type, and that has overhead. This is not a standard Rust library, or even one that I'm able to find within a few minutes of googling despite having used Rust for over a decade.

                The point is that they did the absolute normal expected thing in Rust, and it slowed down the external assembly language library, and after a _lot_ of digging and debugging, they changed the Rust code to be a lot less flexible and more convoluted, and now the assembly language is almost as fast as when it is called from C.

                > Your argument seems to boil down to "Rust claims to be efficient, but it's possible for someone to write inefficient code, and for me to use that code, so therefore those claims are wrong".

                No, that's not my argument at all. Look, the people doing this _obviously_ know Rust, and it took them a _long_ time, and some _really_ ugly concrete low-level concrete code, to take external code and make it perform almost as well as if it had been called from C++.

                To me, that looks like a high-cost non-abstraction.

                • Aurornis 36 minutes ago ago

                  > Look, I wrote " But the point is that the exact same external library code has a _lower_ cost if called [from C]" and that remains a true statement.

                  I don't think you've understood the article at all.

                  The overhead came from the author's own abstractions that were designed to accommodate both the assembly version or the Rust fallback. The assumption was that they take the same types and therefore the abstraction would be zero-cost, but in practice the Rust version had different types and therefore there was extra overhead in the way they were called.

                  If the author had simply done an extern "C" of the function and called it from Rust there wouldn't be overhead.

                  > To me, that looks like a high-cost non-abstraction.

                  The abstractions that caused this probably were not standard Rust library abstractions. The author wrote them as part of the library.

                  You don't need an abstraction at all to just call C functions from Rust. It's build right into the language.

                  If you think the problems in this article are a common Rust failure mode, you haven't understood the article at all. The unique method of calling C functions was something the author wrote, not a standard Rust practice.

        • Aurornis 2 hours ago ago

          > but "zero cost abstractions" implies, well, that you're crawling _up_ the abstraction pyramid, not lost in twisty little side passages

          The zero cost refers to the runtime cost, not the programming complexity.

          • kelseyfrog an hour ago ago

            What's a language with zero complexity-cost abstractions?

            • eptcyka an hour ago ago

              Natural language. It's a language interpreted by LLMs. It is really high level.

              • bigstrat2003 an hour ago ago

                Even that has lots and lots of abstractions which add complexity. For example, figures of speech such as "shooting fish in a barrel".

        • cardiffspaceman a day ago ago

          To me it implies abstraction such as a constructor, but with no overhead compared to the same steps done in some other way.

          • zephen a day ago ago

            Sure, but languages and the problems we solve with them are both multifaceted, so simply pointing to one tool and saying "this is better than the one you have in your toolbox" is fine, but the plural in "zero cost abstractions" kind of implies that most or all the tools are at parity or better.

            • saghm a day ago ago

              It sounds like you're saying that you consider seeing this single instance of someone writing a library with a costly abstraction to be indicative of the entire language ecosystem not fitting the paradigm. This is kind of hard to take seriously; it's not like C++ doesn't have some costly abstractions as well way more embedded into the language itself (e.g. exceptions).

              • zephen 20 hours ago ago

                > someone writing a library with a costly abstraction

                That's not what happened here.

                > it's not like C++ doesn't have some costly abstractions

                This is simultaneously both completely orthogonal to my observation that the Rust FFI is borked, and a great example of a problem that wouldn't happen in C++, because in C++ you could completely ignore the costly abstractions if necessary.

                • Aurornis 32 minutes ago ago

                  > That's not what happened here.

                  Yes, it's what happened here. The article is about debugging the author's own abstraction types that had some incorrect assumptions.

                  You do not need these wrapper types to call C functions. If the author had removed the complex extractions and called the extern "C" function directly (as is standard in Rust) there would not be the additional overhead.

                • saghm 20 hours ago ago

                  > > someone writing a library with a costly abstraction

                  > That's not what happened here.

                  Yes it is. Where do you think the `FFISafe` type that they used came from? It's not anything inherent to how Rust does FFI; it's a type someone wrote in an attempt to try to provide an abstraction, and that abstraction happened to have a cost. There's absolutely no reason anyone has to use it in order to do FFI in Rust.

                  • zephen 19 hours ago ago

                    The extra time was being taken up in the identical assembly language function.

                    Fixing it took wizardry.