7 ms·
The Core of Rust
- khuey 1y agoIronically the "simple" JS program has a bug in it. The documentation for fs.watch is very explicit that the filename in the callback can be null and that you need to check for that. In Rust that fact would be encoded in the type system and the programmer would be forced to handle it, but in JS it's easier to just write bad code. https://nodejs.org/api/fs.html#filename-argument https://nodejs.org/api/fs.html#filename-argument
- sestep 1y agoTrue, but also the loop syntax is simply incorrect, which would have been caught by running it; so probably a better interpretation is simply that the author didn't spend much time thinking about that JavaScript code because it didn't matter for their point.
- masklinn 1y ago> it didn't matter for their point. Which is mostly a lie, since at least half the concepts they gripe about in rust are in the js snippet.
- sestep 1y agoYep fair. I'm not sure why they didn't spend more effort on the JS part, just saying they didn't.
- serial_dev 1y agoBut isn’t it at least part of the problem? The JavaScript code looks completely fine, until the HN comment section finds various subtle bugs that sometimes not even TS can protect you against?
- jynelson 1y agono. the JS program has obvious syntax bugs that TS wouldn't compile. commentors above are right that I was just lazy (ty for the callout, I have since fixed the JS program).
- Waterluvian 1y agoTypescript would require you to check for null before use, which I think makes this a good example of how TS is oftentimes a fairly gentle step up from JS. Or, at least, closer to the correctness of Rust without all the heavy stuff.
- quotemstr 1y agoBut you don't get manual memory management then. No GC, safety, and simplicity: pick any two
- Waterluvian 1y agoThat’s true, two different tools have different pros and cons.
- ori_b 1y agoSure, but GC's not the only upside.
- TylerE 1y agoFor a large number of people including myself, manual memory management is a huge con, not a pro.
- ameliaquining 1y agoYes, but there are use cases where it's a hard requirement.
- kiitos 1y agoyep! but file watcher programs, or http services, or really anything that runs on modern linux servers, are not these use cases!
- koakuma-chan 1y agoDo you manually manage memory in Rust? Because I just write Vec::new or vec![], just like how I would write new ArrayList in Java.
- marcianx 1y agoThere are further bugs: `for path in paths` should be `for (const path of paths)` JS will immediately error on the lack of parens, but the `in` vs `of` iterates over indexes, not values, and those indexes are unfortunately converted to strings (since `for-in` is object field-name iteration). So even TypeScript would not have caught it when the (stringified) index is used as the first argument of `fs.watch()`.
- ptdorf 1y agoAm I blind or where is `kind` coming from? > console.log(`${kind} ${filename}`) It should be `eventType` (string).
- khuey 1y agoYes. It's coming from the Rust code (where the relevant property is named 'kind') because the author didn't actually run their JS snippet. They've (silently) fixed a number of issues people have pointed out (including the one I pointed out) but they still haven't noticed that one.
- andrewmcwatters 1y agoA smaller Rust just sounds spiritually like Zig to me. Like C++ to C.
- bonzini 1y agoRust without safety-by-default, and hence without the borrow checker, is not Rust. A smaller Rust should either remove unsafe constructs (and then you get something more like a new Java/Scala/Kotlin except with aliasing XOR mutability) or keep the pointer/reference distinction (which Zig doesn't have). Zig is more like a smaller C++ than a smaller Rust.
- hamaluik 1y agoThis feels like a fairly uncharitable take. The author conveniently left out all of the things needed to understand that JavaScript version, including async/await, promises, modules, string interpolation, lambda syntax, not to mention the runtime that is running this, etc. You also don’t have to start with a program that invokes 20 concepts at once, every one of those rust concepts can have its own hello world, introducing one concept at a time. Frankly several of them are just fundamental CS concepts.
- masklinn 1y ago> The author conveniently left out all of the things needed to understand that JavaScript version, including async/await, promises, modules, string interpolation, lambda syntax, not to mention the runtime that is running this, etc. And iterators.
- loevborg 1y agoAnd "for of" vs "for in" (the latter typically shouldn't be used)
- cratermoon 1y agoAs I read it, the author is making a point about explicit vs implicit knowledge. In the Rust version the compiler will ~yell at you~ politely point out where your code won't work, while the js version will ... just run, but maybe not work?
- Spivak 1y agoI mean both languages (and programs) have modules, string interpolation, lambda syntax, and a compiler/interpreter. The only thing they really left out is Promises. And you're iterating over an array so there's no understanding of iterators needed. You can write Python for a long time without ever learning about __iter__. In the example Rust program the iterator is exposed. I think if the Rust version only used the for syntax you could say you don't need to know about iterators.
- 1y ago
- deleted 1y ago[deleted]
- IshKebab 1y agoThe closest thing I've seen to "simple Rust" I've seen is Gleam: https://tour.gleam.run/ https://tour.gleam.run/ It's clearly very heavily inspired by Rust.
- raphinou 1y agoI encourage you to take a look at fsharp if interested in another 'simple rust'
- akkad33 1y ago> It's clearly very heavily inspired by Rust The creator has said it's not. It's compiler is in rust though. But Gleam is an entirety different language in terms of paradigms and target runtimes. It can't really replace rust
- IshKebab 1y ago> The creator has said it's not. Well that seems highly unlikely given the huge number of similarities.
- ameliaquining 1y agoWhich similarities are these, that numerous other languages don't also have?
- IshKebab 1y ago* Same names: fn, let, mut, pub, println, etc. * Same everything-is-an-expression style. Blocks evaluate to the last expression in them. * /// Doc comments * ML style pattern matching * Result type * 'todo', 'panic' "Whhaaa but you can find those features in other languages! You literally said ML-style you big idiot!!" Indeed but Rust massively popularised a lot of those features (how many people actually use ML?) and the number of them makes it almost impossible that it isn't at least strongly inspired by Rust. Interestingly they have fixed the tuple syntax issue - it's #(a, b, c) - but have copied the match pattern matching mistake where you can write what looks like a variable name and it becomes a pattern. That mistake has been known since the 70s.
- koito17 1y agoMinor nitpick println can only print things that implement the traits Display or Debug. As a result, Paths cannot be printed directly. Not all OSes store paths compatible with UTF-8. In Rust, all strings are UTF-8 encoded. Thus printing a Path is a lossy operation (i.e. cannot safely be round-tripped). Path exposes a `display` method returning a type that implements Display. This is a fact Rust is encoding in its type system, whereas in JavaScript (and TypeScript), it's not really possible to state "strings internally are UTF-16 and you may need to invoke TextEncoder / TextDecoder to safely deal with paths that are not Unicode". If you fetch from a server sending Shift_JIS text and invoke `response.text()`, you get an empty string at runtime (in my experience). If you aren't experienced in dealing with text encoding issues, I can see this becoming a lengthy debugging session. As others have noted, the JavaScript program has a bug not present in the Rust program, and a syntax error (should probably use for..of, not for..in). The example definitely uses more concepts than "first-class functions". You still have to understand iterators, just like in Rust, and it uses CommonJS instead of ES Modules, but I digress. The usage of async/await and Promises is another concept to teach, and the usage of top-level await is specifically something that wasn't supported in some runtimes (e.g. Node) until recently. It still isn't supported in the latest version of some mainstream JS engines (e.g. Hermes, which is used in React Native)
- tracker1 1y agoI find that understanding thenables/Promises and async-await in JS/TS is emphatically not something a lot of devs really understand. It really shows when you see something like... var fn = async (param) => new Promise((res, rej) => { ... fooLibraryCall(param).then(res).catch(rej); }); I've literally seen similar to this... where devs see wrappers for the callback syntax, then apply the same to thenables and use manual Promises inside an async labelled function. It makes my mind bleed to see it, and I've seen it a few places. Then, of course, there's dealing with module imports and async import() methods and how they operate or get transpiled or split, etc.
- tomjakubowski 1y agoSometimes you still need to work with promises even inside an async context. Imagine an async function which needs to `await Promise.all([...])`. In this case, `then()` can be a useful tool to make new promises from an async call.
- petcat 1y agoI often encounter people that want to learn a programming language and ask if they should pick Rust as their first language. My answer is universally: NO. Learning a first programming language is hard. And Rust will only make it harder since all you're going to do is debug compiler errors all day and never even see your program actually run until it's "perfect". This will be incredibly frustrating and you'll give up. I always tell people to start with Python, JavaScript, or Lua. You can make something fun and interesting for yourself, like a game, and get immediate feedback and you can iterate quickly.
- tracker1 1y agoI would suggest Python or Lua before JS if you want to learn formally, such as following a book/series/class. JS (and TS) just have so much flexibility and many functionalities have been enhanced over the years that depend on the runtime context and build tooling in some cases. Don't get me wrong, I love JS/TS since before the "Good Parts" book ever came out. The only advantage it has as a first language is you can start tinkering directly in the browser... Which is something I use to this day... the debug console in the browser, I can exercise a generated API client before the UI features are flushed out. If you want to learn with the intent of "I want to build $THING." then JS/TS is probably a great language to start with... you will probably want to read something like a for dummies book to start, then bootstrap with a coding ai... and tinker until it works. Note: don't do this for anything security critical when starting out.
- tucnak 1y agoTo be fair, Rust is genuinely just as _hard_ in 10th language capacity.
- stouset 1y agoI really don’t think so, but it probably depends on which languages you’ve used in your life. I’ve spent most of my professional time in C, Ruby, and a decent amount of time dabbling around in functional languages. All of the core bits of Rust from this post more or less clicked immediately for me. The other features are there, but they’re typically not something you need to internalize to comprehend Rust as a whole. The biggest hurdle—as for most people—was learning what the borrow checker is really trying to teach you about the structure of your programs and internalizing those lessons. But having some experience with RAII and good practices around manual pointer ownership in C helped pave a pathway toward understanding those concepts.
- nromiun 1y ago> There’s a famous quote by Bjarne Strousup that goes “Within C++, there is a much smaller and cleaner language struggling to get out.” Within Rust, too, there is a much smaller and cleaner language struggling to get out: one with a clear vision, goals, focus. One that is coherent, because its features cohere. This post is about that language. The problem is that using this "core" of a language never works. Either you need a feature or a library that touch the bad parts you are trying to ignore.
- procaryote 1y agoalso, at least for C++, different people have incompatible ideas of what that core is
- falcor84 1y agoStill, it's much easier if 95% of the codebase uses just the core, and the parts that don't are relegated to known here-be-dragons areas, that are always reviewed by a couple of more experienced engineers.
- akkad33 1y agoAnother post about how Rust is not to their liking because it has things there familiar language does not have. For example the author says exceptions are somehow "simpler" than Result types and it's a downside Rust does not allow you to get a value without checked for error. And complains about ? operator. I think just because you are more familiar with exception style programming does not make it simpler.
- swiftcoder 1y agoI think you misunderstand the direction the author is coming from - Jynn is definitely not a newcomer to Rust who doesn't understand why things in Rust are the way they are
- estebank 1y agoTo drive the point home: https://github.com/rust-lang/rust/pulls?q=is%3Apr+author%3Ajyn514+is%3Aclosed https://github.com/rust-lang/rust/pulls?q=is%3Apr+author%3Aj...
- philjohn 1y agoYep - I came away from this as someone who hasn't touched Rust yet as "Yes, it's complicated, but that's for good reasons, because all of these complicated things work very well together to make writing software better ... when that doesn't happen you have things like Pythons pattern matching which is yuck".
- akkad33 1y agoMy mistake
- tracker1 1y agoI didn't read the article as being particularly critical of Rust at all, only demonstrating that it has a lot of concepts that you need to know in a coupled way in order to do most functional things in the language. It just means it's a slightly harder language to learn. I've experienced this myself when starting out and just wanting to make $THING in Rust. A lot of looking things up... then trying it out... then seeing the compiler errors.. then looking up WTF they mean when you don't have solid grasp on X, Y and Z in Rust. Then going down the rabbit hole of mut and clone in order to do what you want... often just cloning because it's easier, even if less performant, only later to understand (a)rc etc. In another language, you may well get something to run, even if not correct, which can be far more satisfying to correct an incorrect behavior/bug then to have the compiler yelling at you from the start (slowly)... it's a slower and more painful feedback loop to work with. It isn't bad so much as different. That doesn't mean it isn't real, or that I or TFA are bashing Rust.
- tracker1 1y agoAnyone else get completely side tracked as soon as you saw the shebang (self-executing rust scripts)? MY mind kind of exploded in a similar fashion to when I discovered Go could do the same. It's definitely a nifty feature and can see it getting a lot of basic usage. I've seen a couple projects that do similar with rust to control build and testing pipelines, this could be a good alternative in those cases. That said, I mostly just use Deno + TS for my shell script needs beyond simple bash. Mostly in that JS is hands down the language I know the best (28 years), close would be C# (24 years) for me. I was also an early adopter of Node. I also think that dealing with shared/centralized packages is an easier option for Deno than Node, Python or other languages/environments. The cargo front-matter here seems to work similarly.
- TylerE 1y agoThat’s just a basic Unix thing. Any file starting #!/some/path just means for the shell to invoke that command and pass the contents of the file on stdin.
- ameliaquining 1y agoMost languages currently do not support this in a way that lets you specify dependencies from a package manager. And some don't support it at all; most C and C++ toolchains, for example, don't have a way to compile and run a single source file in a single command.
- tracker1 1y agoExactly, that alone makes it far more useful/portable in practice than a lot of other languages for this type of thing. A python file can have a shebang, but it'll need a bunch of other files around it for module references, etc. Not to mention initialization/setup, etc. The fact that dependencies are referenced in the file and automatically handled at runtime (first or repeated) is a really nice feature to have... it's expressly why I started using Deno over other options for this.
- epage 1y ago
- t8sr 1y agoI've taught programming to some people who had no previous experience with it, and I can tell you that the list of concepts you have to learn at once is basically as long for Python, the quintessential "beginner" language. The author's argument feels intellectually dishonest for that reason. Especially glaring is the comparison to JavaScript. The latter has an insane amount of concepts to deal with to do anything, including some truly bizarre ones, like prototypes. Rust is hard to learn, IMO, for precisely two reasons: 1) The borrow checker is in an uncomfortable place, where it's dumb enough that it rejects perfectly valid code, but smart enough that it's hard to understand how it works. 2) As the author points out, there are a lot of levers available for low-level control, precise allocation, etc. With respect to the second point, the author describes a language he'd like to see: green threads, compiler deciding on allocation, fewer choices and easy thread safety. This language already exists (minus algebraic types). It's called Go. It's perfectly fine, well-designed and good for beginners. Some people don't like its aesthetics, but that's not reason enough to invent it again, only with Rust-inspired syntax.
- TylerE 1y agoThe venue bigger issue with rust as that the compiler is so bitchy it is actively hostile to incremental add-a-line-at-a-time incremental development. Especially unused variables being a hard compilation error, not a warning.
- estebank 1y agoUnused variables are a warning: https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=832eaad93c08535625555c5def12a003 https://play.rust-lang.org/?version=stable&mode=debug&editio...
- Ar-Curunir 1y agoWhat? Unused variables are warnings in Rust. Are you thinking of Go?
- J_Shelby_J 1y ago> the list of concepts you have to learn at once is basically as long for Python, the quintessential "beginner" language IMO, Python is great. But deploying Python is more work than learning Rust, oh and the tooling is something that requires continual education: I hear UV is what all the serious python teams are using now. Better learn it or be left behind! Meanwhile, vanilla Rust has everything you need. I'm glad I understood sunk cost fallacy and got out of Python after many months of coming up to speed with it.
- sarmadgulzar 1y agoI know I'm biased, but Rust is the closest thing we have to a perfect programming language. Is the borrow checker a pain in the ass? Yeah. But is it necessary? Absolutely. Imagine writing the same buggy program in C, deploying it, and then it blows up at runtime—you still have to fix it, right? A bug is a bug, and it needs fixing. The difference is Rust forces you to deal with it before you even get a binary, while with C you might get a 3 a.m. wake-up call trying to figure out what went wrong. So it’s not that Rust is harder, it’s just different. It takes a paradigm shift in how we think about writing safe and secure code. Change is uncomfortable in general for humans and that paradigm shift is precisely why most (I hope not) people feel this way about Rust.
- tucnak 1y ago> Is the borrow checker a pain in the ass? Yeah. But is it necessary? You've missed the primary point of the post entirely. Borrow checker per se is not the problem; it's the sheer amount of everything. There's multiple ideas of perfection. Those of us to have very much enjoyed ostensibly imperfect Rust of 2018 find this particular, current flavour unappealing. It may as well be capable tool in deft hand, however, as-is the case with everything in life, you cannot help but ask yourself THE question; is it worth my effort? For me personally, if I were looking for better C/C++ in 2025, I would choose Zig before Rust any day of the week (one exception being Postgres stuff, pgrx ecosystem that is really special!) But then again, anything beats writing C for a living.
- metaltyphoon 1y agoTraits, generics, ownership, RAII shows up in many languages, so what other concept outside of lifetimes does Rust introduces?
- ridiculous_fish 1y agoAffine types, variance, higher-rank trait bounds, phantom data, MaybeUninit, and the whole macro and proc-macro systems are some examples of concepts that I found to be challenging when learning Rust. Dyn-safety is another but I had encountered that previously in Swift.
- hedgehog 1y agoHaving written a moderate amount of both Rust and TypeScript they seem different but I wouldn't say projects in one are significantly simpler than projects in the other. Rust itself feels a little more complicated than TypeScript, but more carefully thought out. TypeScript has more cruft and legacy footguns. Rust tooling is much better (and faster). For cranking out web front end code TypeScript will get the job done faster, most other needs I run into are easier solved using either Rust or Python when starting fresh is an option.
- aeldidi 1y agoEDIT: I’m leaving the comment up so the replies make sense, but I completely missed the point here. That’s what I get for writing dismissive hacker news comments on my lunch break! I find it kind of hard to take this seriously since the JS snippet has a glaringly obvious syntax error and two glaringly obvious bugs which demonstrate that the author didn’t really think too hard about the point they’re trying to make. I understand the point they’re trying to make, that being that rust forces you to explicitly deal with the complexity of the problem rather than implicitly. It’s just that they conveniently ignore that the JavaScript version requires the programmer to understand things like how async await works, iterators (which they use incorrectly), string interpolation, etc. Just using typescript type annotations alone already gives the js version nearly all the explicitness of rust.
- jynelson 1y ago> I understand the point they’re trying to make, that being that rust forces you to explicitly deal with the complexity of the problem rather than implicitly This is not the point I am trying to make.
- aeldidi 1y agoI read it again and understand what you mean. I apologize for commenting like that so quickly, I was on my phone and typed that comment out before I really had time to digest the contents.
- kiitos 1y ago> Let’s look at a Rust program that does something non-trivial: ... (a bunch of highly specific explanations of deeply technical details from the very short program source code) what does this program actually do? all of this extraordinarily subtle analysis, about rust language specific properties, specific to this individual program, and no actual summary or description of what the program is supposed to do! what it does is print out a line whenever a file, matching certain criteria, is modified. that's it. and as such it's an almost pitch-perfect example of exactly what's difficult with rust as a language. what this program does is trivial to describe and should have a commensurately simple implementation. but rust makes the programmer care about a dozen? dozens? of details that have no relevance to the problem domain at hand. for people who are just hungry for complexity this is an exciting challenge that they can tackle and solve! but that complexity, that challenge, is self-inflicted, almost always incidental and unnecessary work
- zozbot234 1y agoBut the implementation is simple, especially for such a high-performance language. It fits on less than a single printed page. What more could you expect?
- kiitos 1y agosimple isn't measured in terms of SLoC, it's measured in terms of cognitive complexity the article itself says, clearly, that the (short) rust program requires knowledge of a significant number of non-trivial language features, as well as the behavioral outcomes of all of their combinatorial interactions -- approximately none of which are relevant to the problem that is being solved by that program! what I expect is that a language adds as little cognitive complexity (overhead) as absolutely possible, when it is used to express a solution to a given problem
- mynameisash 1y ago> what this program does is trivial to describe and should have a commensurately simple implementation Why do you think that a simple implementation follows from a simple explanation? As an example, see XKCD 1425[0], whose transcript I include here: > Cueball: When a user takes a photo, the app should check whether they're in a national park... > Ponytail: Sure, easy GIS lookup. Gimme a few hours. > Cueball: ...and check whether the photo is of a bird. > Ponytail: I'll need a research team and five years. > In CS, it can be hard to explain the difference between the easy and the virtually impossible. [0] https://xkcd.com/1425/ https://xkcd.com/1425/
- ameliaquining 1y agoSo what exactly is the "much smaller and cleaner language struggling to get out" of Rust? If I'm understanding the post right, that language still has references, lifetimes, traits, enums, etc., because all of those features cohere; you can't remove just one and expect the rest of the language to still work. Once you grant all those features, your language isn't much smaller or cleaner than Rust; your language pretty much is Rust. The last section gives two different hints as to what this "smaller and cleaner" language might be, but neither of them fully makes sense to me. First, withoutboats's "Notes on a smaller Rust". That post and especially its sequel are great and I like them a lot, but the title is fairly misleading as to what they're getting at. The language that boats sketches out in those posts has significantly different design goals from Rust; in particular, it abandons the requirement of low-level programmer control over runtime behavior, and so is unsuitable for many use cases that Rust is used for. The idea, rather, is to explore what lessons Rust can offer for the design of a language with more "mainstream" requirements (i.e., one that can afford things like a tracing garbage collector, and wants to avoid Rust's downsides compared to other popular languages, like slow compile times and heavy syntactic salt). That language is not "struggling to get out" of Rust; Rust doesn't want to be it. Second, "In a manner of speaking, that smaller Rust is the language I fell in love with when I first learned it in 2018. Rust is a lot bigger today, in many ways, and the smaller Rust is just a nostalgic rose-tinted memory." I've explained above why I don't think boats's proposed "smaller Rust" is anything like the real Rust was at any point in its history (at least after the very early days, once the designers figured out that they were targeting C++'s niche). In most fundamental respects, Rust hasn't changed that much since 2018, and a lot of the changes (like the new editions) are about making it more syntactically flexible and increasing the fraction of sensical programs that compile. That said, there are two big exceptions: async and const, which were much more minimal in 2018 and have since expanded to big complex meta-features with many interlocking parts that weren't part of the language's original core. If the claim is specifically that Rust was smaller and cleaner before async and const, then by all means, say that! But the post doesn't, leaving us to try to figure out what was meant.
- zozbot234 1y ago> So what exactly is the "much smaller and cleaner language struggling to get out" of Rust? Austral? https://austral-lang.org/features https://austral-lang.org/features
- ConanRus 1y ago[dead]
- tialaramex 1y agoThe Bjarne quote is basically sales pitch for a recurring rationale to make C++ worse and worse. It was, I suppose, not unreasonable to assume Bjarne was sincere the first time, but that was a long time ago. Here's how it goes: 1. “Within C++, there is a much smaller and cleaner language struggling to get out” 2. However just subsetting the language to get at the smaller one would not be a cleaner language. Instead we must first make a superset language, adding features, then we can subset this new language to reach our smaller but cleaner C++ 3. Step one, superset will land in C++ N+1. Planning of that "subset of a superset" will need to wait until we've completed that work. 4. C++ N+1 is an even clunkier behemoth. Rinse and repeat. I don't understand why people who've seen this happen more than once would stick around. You're not going to get the "smaller and cleaner" language after step two, there is no step two, it's just going to be step one again and then step one again, and then step one again, forever.
- tele_ski 1y agoreminds me of the classic https://xkcd.com/927/ https://xkcd.com/927/ not exactly identical to Bjarne's quote but similar. I'm quite familiar with C++ as well and this just jives so much, each standard is just almost exponentially more complicated than the last, and while there are good changes they don't necessarily fit well with the prior version and its just a mess, I still maintain two OSS libs but I don't use the language anymore.. so its a question of how long I put up with it at this point. Rust is such a breathe of fresh air coming from c++11/14/17/20 but its still a behemoth if you don't know the entire thing, I think this article is pretty spot on with that.
- meltyness 1y agoI find Rust pretty cohesive and consistent in its semantics. Accomplishing different tasks involves less sugar than other languages like this article seems to focus on. Generally all of the interfaces conform to the patterns in the mem module. If you want to understand the structure of everything else unambiguously it would be best to start there: https://doc.rust-lang.org/std/mem/ https://doc.rust-lang.org/std/mem/
- Naru41 1y agoI think Rust is the biggest winner that has from LLM support. When I got an compile error, it is painful without LLM to reverse-thinking how to re-write something and why it needs to be written that way.