A Look at Rust from 2012

(purplesyringa.moe)

148 points | by todsacerdoti 8 days ago ago

68 comments

  • steveklabnik 9 hours ago

    Fun trivia fact: this is basically the exact moment I first encountered Rust.

    I’m also generally very glad at where it went from here. It took a tremendous amount of work from so many people to get there.

    • ramon156 8 hours ago

      Hey, I remember your "Rust 1.0, ten years later" post. Good stuff!

  • pton_xd 5 hours ago

    I was really excited about the idea of a modern statically typed language with green threads ala Erlang / BEAM. I lost interest when Rust moved away from that direction and became focused on zero-cost abstractions instead.

    • steveklabnik 5 hours ago

      It certainly was a big shift, a lot of people both had your opinion and had the opposite, for sure.

      Do you think Go fulfills that for you today or do you think there's still space for a new language here?

      • throwaway17_17 2 hours ago

        Not parent, but I think there is certainly space for a Typescript-esque language for Go. If the parent commenter was looking for a static type system, the implication is they would probably want a more functional language inspired type theory. Go’s runtime is not the BEAM, but it is usable for many of the tasks Erlang is pitched for.

        I can readily see a Haskell inspired System F derivative the compiles down to valid Go, or a more flexible, special cases type theory that encompasses all of Go like Ts->Js. Likely a ‘transpiler’, I hate that term, to Go implemented in Go and you have a self-contained language with more advanced type features and Go’s green thread runtime.

        • jbreckmckye 41 minutes ago

          I think a functional, or orchestrated programming / BEAM like design, would do better than the various initiatives to build "Go++"

          Generally Go programmers like their language and are pretty resistant to changes (IME). But for those who use Go _despite_ the language itself (like me), it's probably an easier sell

        • NortySpock an hour ago

          https://github.com/MadAppGang/dingo

          This project proports to be typescript for golang

      • pdimitar 2 hours ago

        As a person who actively uses Elixir, Rust and Go (in that priority order) to me there is a maddening gap between Rust and Go.

        While Go has the goroutines and they have made concurrent and parallel programming accessible to many, they are a rather raw material that's easy to abuse and use wrongly (leaks, deadlocks, and don't even get me started on writing to a closed channel -- instant panic and program abort).

        Rust async is also too raw but in another way: gets wordy / verbose and too implementation-oriented way too quickly -- I never wanted to care about Pin<Box<???>> or what must this or that Future implement in order to be eligible for usage in `select` and whatnot. Those things should have been hidden behind a DSL much like `select` and `async` itself are a DSL / macros / state-machines of sorts. Rust's async just seems... I don't know... unfinished. Zero disrespect is intended (and I do recognize you by your username), I love Rust and I never pass an opportunity to whip up an internal CLI tool with it and my most consulting engagements have resulted in teams highly appreciating such tools, but I can't shake the feeling that Rust's async could be more... polished.

        Both Rust's and Go's async mechanics leave me with the impression that somebody thought that they gave the devs enough LEGO building blocks and called it a day. I don't judge. I understand. But as a user of the languages I also have the right to find their async facilities less than ideal.

        Erlang / Elixir / Gleam / LFE on the other hand stand on a runtime that has exhaustively analyzed a ton of async scenarios and cover them very well (minus stuff like filesystem operations being centralized through a singleton runtime agent, something you can opt out of, thankfully).

        So I'd say both Rust and Go are ripe for either disruption or courageous backwards-incompatible modifications. Their async implementations simply did not go far enough.

        And don't get me wrong, I love both and do my best to use them regularly. But it's a sad reality that their "unfinishedness" led to a plethora of footguns that became a badge of honor if you get to know most or all of them, as in: know how to avoid them. Which I don't know why many see as a desired state of affairs. Job security, I suppose.

        I would kill for something as terse and explicit as Go but as super strict as Rust but that also has 100% finished async semantics, and has a faster compiler than Rust but optimizing as aggressively as it as well. Yeah, I know: what color do I like my dragon?

        All that being said, Rust is the closest we have to a perfect language currently. And that's kind of sad because it has a few things that it really needs to fix if it wants to keep gaining mind-share. I personally find myself reluctant trying to build a career with it. But I'll not digress further.

      • umanwizard 2 hours ago

        I’m not OP, but IMO go cannot be called a “modern language”. The go ideology seems to be that such basic “modern” ideas as sum types are just pointless intellectual games, akin to Haskell type astronaut behavior, or that they’re too advanced for most programmers to understand.

    • nahuel0x 4 hours ago

      check Gleam

  • junon an hour ago

    I see now why my first attempt at Rust around this time failed miserably. I had forgotten about a lot of this, and remember trying to make liblua bindings at the time for something I was working on. I wrote Rust off as too cryptic to get anything done with.

    I'm really, really glad I've since picked it back up post-1.0.

  • ramon156 8 hours ago

    I actually liked @T because you would pronounce it as "At T".

    You could say "The address at T". Curious why people hated it, I might be missing something.

    • steveklabnik 6 hours ago

      @T had a number of issues. The first was just that it was weird. People tend to not like weird things. Rust developed a reputation for "that language with a bunch of pointer types that are all weird."

      The real reason it was removed in the end was just that it elevated a library concept into syntax. Today's Arc<T>/Rc<T> split isn't really possible in an @T world, for example. Shared ownership is a good concept, but you don't need special syntax to indicate it.

      • zozbot234 6 hours ago

        > The real reason it was removed in the end was just that it elevated a library concept into syntax.

        Rust still does this in all sorts of silly ways, such as the ! type. What's the point of wasting an entire symbol that could have plenty of alternate uses on something that's so rarely used and could easily be defined as either a library type (empty enum) or at least be given a custom keyword, such as `never`? (Introduce it over an edition boundary, if you must preserve backwards compatibility.) The fact that it involves some compiler magic is no excuse; that's why Rust uses "langitem" markers within its core library.

        • steveklabnik 6 hours ago

          The standing joke for the last few years is that "the never type is named after its date of stabilization."

          I certainly don't disagree that Rust has flaws, for sure. I think this particular one is pretty far down the list, though. I'm not sure what else I'd want to use ! for, and by virtue of it not being used so often means that it's much less of a pain than @T would have been, though I would also argue that 2012 Rust used ~T and @T far more than contemporary Rust does (I still remember pcwalton's mailing list post about how you didn't have to use ~ for comparing strings!) and so was even more painful at the time than would be now.

          • iknowstuff 4 hours ago

            Swift and TypeScript use ! sort of like .unwrap(). Probably a better use of it than "never" tbh.

            • ramon156 23 minutes ago

              We actually use this version of never a lot in our code at $WORK

              ```

              export function never(message?: string): never {

                throw new Error(message ?? 'Reached an impossible state');
              
              }

              const [foo = never()] = dbQueryThatReturnsOne();

              ```

              I guess it's en par with .unwrap()

            • bryanlarsen 3 hours ago

              If ! was just used as never it could still be used as an operator, because those are different contexts AFAICT. However, its use in macro invocations seems likely to be more difficult to differentiate from operators.

            • steveklabnik 3 hours ago

              I'm not completely opposed but I'm also not sure syntax sugar for unwrap is a great idea.

      • MangoToupe an hour ago

        > The first was just that it was weird.

        Compared to what?

        • steveklabnik 35 minutes ago

          People just found the trio of &T, @T, and ~T to be strange and confusing. Lots of Perl comparisons, many people really dislike punctuation of any kind, it seems.

          Most languages only have one kind of pointer, and they tend to use & and * as operators for them.

          • MangoToupe 7 minutes ago

            Sure, but people also find pointers and references confusing (& certainly their distinction). Literally all programming is considered weird if you talk to the right person.

            I would argue as a rule of thumb, anyone who focuses on syntax over semantics has little to contribute until they write ten thousand lines in the language. Perl is a great example of how it still fails after this test passes. Rust feels a lot more like java and c++ now, and not in a good way. It could have done more to improve on basic readability than where we ended up, and people still bitch about basic tenets of the language like "lifetimes" and "not being enough like java".

            • steveklabnik a few seconds ago

              You can stand on principle, or you can recognize that semantics is important, and syntax isn’t really, and therefore, accepting feedback about syntax is a fine thing to compromise on.

              I also agree that you can’t listen to everyone, but this feedback was loud and pervasive.

  • srott 8 hours ago

    > rest of the post is me trying to make sense of the tutorial on borrowing. It has fried my brain and negatively affected my skills in modern Rust, so be wary

    I think that tutorial discouraged me from really getting into Rust

  • ravenical 5 hours ago

      continue was called loop for some reason
    How strange! Does anyone know why?
    • steveklabnik 5 hours ago

      There was an early rule that Rust keywords should be five characters or less. I would guess it's because of this rule. I believe loop turned into cont to satisfy this rule, and then eventually we relaxed the rule, and it became continue.

      • iknowstuff 4 hours ago

        Whoa, do you know who and why came up with that? So strange, making it less readable on purpose?

        • steveklabnik 3 hours ago

          IIRC it was just a personal preference of Graydon's back then. I'm also not sure it was intended to live forever, just something to try and nudge things in a particular direction.

          Terseness doesn't inherently mean less readable.

          I do think that that rule is probably not one that would be good permanently.

    • kuresov 5 hours ago

      I could see it… like “loop back around” or “continue loop”. I think good old “continue” is better and more familiar though :)

  • Macha 6 hours ago

    I think this was a year or two before I got to rust - some of these things still existed then (bare traits, no NLL, the ecosystem was only halfway onto cargo), while others (the old pointer type syntax) had already gone.

  • assbuttbuttass 9 hours ago

    Very interesting to see the ML influences like ~ for unary minus, unscoped enums, mut on specific struct fields...

    It seems like over time, a lot of that was replaced with C++-style syntax and semantics. Presumably to make the language appeal more to C++ devs

    • ahoka 9 hours ago

      People wanted a new C++ and they made Rust into it.

    • nine_k 8 hours ago

      AFAICT the need to resolve unscoped enum values, combined with type inference, is one of the things that makes the Swift compiler so slow.

    • ux266478 3 hours ago

      Which is funny, because as a C++ developer it makes it less appealing.

    • echelon 9 hours ago

      Rust looks nothing like C++.

      It looks like Ruby.

      The generics look like Java.

      • tialaramex 7 hours ago

        How do you feel the generics "look like" Java ?

        Implementation-wise they're the same trick as C++, monomorphization.

        Stylistically they're not very like either, however the effect is more like C++ because Rust idiomatically prefers to constrain functions not types so e.g. it's fine to talk about HashMap<f32, f32> a hypothetical hash table of floating point numbers mapped to other floating point numbers - even though we can't use such a type because if we try to insert into it we'll be told that insert requires its key parameter to implement Eq and Hash, which f32 doesn't because of NaN.

        In both C++ and Java as I understand it these constraints live on the type not the functions associated with that type, although C++ does not have the same constraint here and is perfectly willing to try to make a hash table of floats... but where a constraint lives on a function in C++ it would behave similarly to Rust due to SFINAE - the function won't match so your diagnostics say there's no such function, probably worse diagnostics than Rust but that's par for the course in C++.

        • echelon 6 hours ago

          And here I was thinking we were talking about the syntax.

          My Ruby claim doesn't hold much weight either if we're talking about the actual implementation.

          C++ templates look like an entirely new language within the language.

          Rust and Java make generics fit within the aesthetics and ergonomics of the language.

          If anything feels "bolted on" to Rust, it's proc macros and (to a lesser degree) async.

          • tialaramex 3 hours ago

            Oh I see. Yeah, perhaps slightly for the syntax. I suppose Java's idiom of naming classes (its only user defined types) with capital letters stands out as more similar and so in Java our growable array of geese is ArrayList<Goose>, in Rust it's Vec<Goose> but in C++ std::vector<Goose> or perhaps std::vector<goose> if we're copying the style of the standard library.

            It doesn't feel like very much, but now that you spell it out I guess I do see it.

          • ux266478 3 hours ago

            > C++ templates look like an entirely new language within the language.

            Templates cover more than just generics. Java full-sale lifted its generics syntax from sepples. I'm curious how you draw the line between the two, when all 3 of them use the angle bracket declaration lists bolted onto the symbol name, a unique style invented by CFront 3. Compare with the generics syntax found in contemporaries like ML, Miranda, Ada, Modula-3 and so on.

      • ninkendo 7 hours ago

        Other than the `|var|` syntax in closures, I can't think of a single way Rust looks like Ruby. I mean that seriously, there is almost no other similarities.

        • echelon 6 hours ago

          Don't forget expressions and block expressions, and all of the Ruby-esque syntax sugar around them. How expressions work with functional methods.

          I write a lot of chains with block expressions that almost look 1:1 with Ruby.

          • nicoburns 5 hours ago

            There's definitely some Ruby influence (closures syntax in particulary), but I think I'd argue that Rust syntax is closer to JavaScript/TypeScript than anything else.

          • 5 hours ago
            [deleted]
        • jjtheblunt 6 hours ago

          i suspect the example was syntax like a.b().c().d(10)

      • dhosek 7 hours ago

        Java Generics look like C++ templates and Rust generics act much more like C++ Templates than Java Generics.

        • dhosek 7 hours ago

          Also, “new C++” refers less to syntax and more to role in the development ecosystem.

  • mkornaukhov 9 hours ago

    > I’m happy with how Rust turned out.

    I agree, with the possible exception of perplexing async stuff.

    • bryanlarsen 8 hours ago

      I was really hoping that there'd be movement on a comment without-boats made in https://without.boats/blog/why-async-rust/ to bring a pollster like API into the standard library.

      Rust has very good reasons for not wanting to bless an executor by bringing it into the standard library. But most of those would be moot if pollster was brought in. It wouldn't stifle experimentation and refinement of other approaches because it's so limited in scope and useless to all but the simplest of use cases.

      But it does in practice solve what many mislabel as the function coloring problem. Powerful rust libraries tend to be async because that's maximally useful. Many provide an alternate synchronous interface but they all do it differently and it forces selection of an executor even if the library wouldn't otherwise force such a selection. (Although to be clear such libraries do often depend on I/O in a manner that also forces a specific executor selection).

      Pollster or similar in standard library would allow external crates to be async with essentially no impact on synchronous users.

      • nicoburns 5 hours ago

        `pollster` in the stdlib would probably make sense. But of course there's nothing stopping anyone from using the `pollster` crate today.

        • bryanlarsen 3 hours ago

          Pollster in the standard library provides several major benefits outside of just using it yourself.

          - it provides an incentive for libraries to be pollster compatible, rather than requiring tokio. And pollster compatible means executor agnostic.

          - libraries would document their library with pollster usage

      • iknowstuff 4 hours ago

        Not quite yet. Crates like reqwest and hyper tend to use tokio's io types internally to set up the sockets correctly and send/receive data at the right time. Those might have different APIs than the thread-pausing sync APIs.

        Sans-IO crates exist but are kind of annoying to schedule correctly on an IO runtime of choice. Maybe lending iterators could help idk

    • vablings 9 hours ago

      I feel async is in a very good place now (apart from async trait :[ ) As a regular user who isn't developing libraries async is super simple to use. Your function is async = it must be .await and must be in an async runtime. Probably as simple and straightforward as possible. There are no super annoying anti-patterns to deal with.

      The ecosystem being tokio centric is a little strange though

      • leshow 6 hours ago

        I love Rust and async Rust, but it's not true that there aren't annoying things to deal with. Anyone who's written async Rust enough has run into cancel-safety issues, the lack of async Drop and the interaction of async and traits. It's still very good, but there are some issues that don't feel very rust-y.

        • junon an hour ago

          I don't really appreciate the superlative here as I too have not run into cancel safety issues in practice.

        • pornel 5 hours ago

          I've been writing async Rust for as long as it existed, and never ran into any cancel-safety issue. However, I also never used tokio's select macro.

    • treyd 7 hours ago

      The system Rust has is a lot better than that of Python or JavaScript. Cleanly separating construction from running/polling makes it a lot more predictable and easier to understand what's happening, and to conveniently compose things together using it.

      • phplovesong 6 hours ago

        Thats putting the bar pretty damn low.

    • echelon 8 hours ago

      I write and use mostly async code, and I cannot for the life of me understand the async hate.

      What do you want Rust to do differently?

      What language does async right?

      How did Rust not reach its async goals?

      Rust even lets you choose the runtime you want. And most big libraries work with several runtimes.

      • mkornaukhov 7 hours ago

        I do write mostly async code, too.

        There are several ~~problems~~ subtleties that make usage of Rust async hindered IMHO.

        - BoxFuture. It's used almost everywhere. It means there are no chances for heap elision optimization.

        - Verbosity. Look at this BoxFuture definition: `BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;`. It's awful. I do understand what's Pin trait, what is Future trait, what's Send, lifetimes and dynamic dispatching. I *have to* know all these not obvious things just to operate with coroutines in my (possibly single threaded!) program =(

        - No async drop and async trait in stdlib (fixed not so long ago)

        I am *not* a hater of Rust async system. It's a little simpler and less tunable than in C++, but more complex than in Golang. Just I cannot say Rust's async approach is a good enough trade-off while a plethora of the decisions made in the design of the language are closest to the silver bullet.

      • ori_b 4 hours ago

        > What do you want Rust to do differently?

        Lean into being synchronous. Why should I have to manually schedule my context switches as a programmer?

        • simonask 2 hours ago

          Because async and sync programming are two fundamentally different registers. There are things you can do in one that you can’t with the other, or which have dramatically different tradeoffs.

          As an example: Call N functions to see which one finishes first. With async this is trivial and cheap, without it it’s extremely expensive and error-prone.

          • jacquesm 3 minutes ago

            The actor model proves that that isn't really as fundamentally a difference as you make it out to be. Write synchronously, execute asynchronously, that's the best of both worlds. To have the asynchronous implementation details exhibit themselves at the language level is just a terribly leaky abstraction. And I feel that if it wasn't a fashionable thing or an attempt to be more like JavaScript that it would have never been implemented in the way it was in the first place.

            Async makes everything so much harder to reason about and introduces so many warts in the languages that use it that I probably think it should be considered an anti-pattern. And I was writing asynchronous code in C in the 90's so it's not like I haven't done it but it is just plain ugly, no matter what syntactic sugar you add to make the pill easier to swallow.

          • ori_b an hour ago

            Do you mean RPCs, or dispatching to threads?

            If not, your async code is a deterministic state machine. They're going to complete in the same order. Async is just a way of manually scheduling task switches.

  • OhMeadhbh 5 hours ago

    I encountered Rust sometime around 2010. I was working a couple of blocks away from Mozilla's Mountain View office and would often overhear people talking about it at Dana Street Coffee Roasting. A couple years later I was working at Mozilla trying to unf*ck their TLS and libpkix implementations. The team rocked, but management sucked. The best part about it is I kept bumping into Brendan Eich and having great conversations about Lisp. I can't remember if P. C. Walton worked there, but several occasions he was in the office and gave me a VERY good, VERY succinct description of the language.

    I wrote a fair amount of Rust code in 2012, none of it on a real project like servo. All of it just code to try to understand what the language was trying to make easy. None of that code compiles any more. (Or enough of it fails that I stopped looking at it.)

    It's not so much a "critique" as it is a confirmation that when the crustaceans tell you the language definition isn't finished yet, believe them. I like the feel of Rust much more than C/C++, but I have C code I wrote in 1982 that still compiles and does what you think it should do. C++ code from 1990 still seems to compile. I have Rust code from 2014 that won't even compile.

    Rust is a cool language and I hope it eventually settles down enough to be considered for "real" projects. I've done a little bit of Ada in the last year and I really, really want something better. But... reverse in-compatibility is a deal-breaker for some corners of the commercial world.

    And yes, I know that (like Python) you can build an environment that lets you continue to compile old code with old compilers and some old code with new compilers. But the projects I'm talking about have life-times measured in decades. Will rustc in 2055 be able to compile a program written today? It doesn't seem to be on the top of minds of most of the Rust community.

    I'm not saying Rust is ugly. In fact, I really like some aspects of the language. And post 1.0 is MUCH better than pre 1.0. But if we could go for a few years without breaking changes that would be nice.

    • steveklabnik 5 hours ago

      Rust achieved 1.0 in 2015, three years after you wrote that code in 2012. Stability wasn't guaranteed until then. Afterwards, it has been. Code from 2015 still compiles today. It's no surprise that 2014 code doesn't compile, as it came before those suggestions.

      > I hope it eventually settles down enough to be considered for "real" projects.

      Rust is being deployed for real projects at pretty much every major tech company at this point, and is used on the critical path of real infrastructure.

      > Will rustc in 2055 be able to compile a program written today? It doesn't seem to be on the top of minds of most of the Rust community.

      This has been a very strong focus of the Rust project for a long time; the reason you saw so much breakage from 2010-2015 was to make sure that it was in the state that we'd be okay with making it stable, and then the track record from 2015 to now has been excellent. There have been a few exceptions, but they've generally been quite small, and needed for soundness fixes.

    • asa400 2 hours ago

      > Rust is a cool language and I hope it eventually settles down enough to be considered for "real" projects.

      I keep seeing folks with this "when will Rust be ready" sentiment and it feels a bit dated to me at this point.

      At my last job we built machine control software for farm equipment (embedded Linux, call it firmware if you like). The kind of thing that would have been in C or C++ not long ago. Worked great, Rust itself was never the issue. Code from the very first versions continued to work with no problems over years of feature additions, bugfixes, rewriting, edition upgrades, etc.

      The job before that, my team wrote a large library of 3D geometry analysis algorithms code that powered some fun and novel CAD manufacturing tools. In Rust. Worked great. It was fast enough, and crucially, we could run it against user-provided data without feeling like we were going to get owned by some buffer overrun. 10 years earlier it 100% would have been in C or C++ and I would have been terrified to throw externally generated user data at it. We were able to do what we needed to do and it served real paying users. What more do you need?

      Rust is everywhere. It's in the browser. It's in databases. It's in container/VM runtimes. It's in networking code. It's in firmware. It's in the OS. It's in application code. It's in cryptography. It's in Android. Rust is all over the place.

      The only other thing I can think of with a similar combined breadth and depth of deployment to Rust on "real" projects (other than C/C++) is Java.

      If I needed something to both work and be maintainable by somebody in 2055, Rust is one of the few things I'd bother to put on the list, alongside C, C++, Java, Python, and Javascript.

    • tialaramex 5 hours ago

      What you've written at the end there is a critique of Rust in 2012, pointing out that it's not a stable language, which, it isn't, as reflected in its versioning, in 2012.

      But a few years later, in 2015, Rust 1.0 shipped. So the stability really firms up from there.

      I happen to have in front of me the first commit of the first modestly sized piece of software I wrote in Rust in April 2021. Which compiles today just fine and works exactly as it did when it was written, on this brand new Rust toolchain.

    • ux266478 2 hours ago

      > I'm not saying Rust is ugly

      I'll definitely say that. It's my biggest problem with the language. Type variable declaration lists, pub keyword instead of export lists, macros instead of functors, out-of-line method declaration, special keywords and symbols all over the place that could have just been built-in type constructors, module accessor is the horrible ::, which synergies with a weird decision to nest modules extensively so that code is even noisier.

      Rust is a very ugly language to me. Ugly enough that while I like many aspects of its semantic design, I will never use it personally. I would rate it to be about as ugly as Ada, just for different reasons.