25 comments

[ 4.0 ms ] story [ 44.1 ms ] thread
Ironically 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

Am I blind or where is `kind` coming from?

> console.log(`${kind} ${filename}`)

It should be `eventType` (string).

A smaller Rust just sounds spiritually like Zig to me. Like C++ to C.
This 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.

Not really, he explicitly makes the point that it's easier to write useful simple programs in Javascript without the extra stuff, whereas in Rust you need to know about a whole lot of things to make the equivalent simple program.
(comment deleted)
The closest thing I've seen to "simple Rust" I've seen is Gleam: https://tour.gleam.run/

It's clearly very heavily inspired by Rust.

On the homepage:

>Black lives matter. Trans rights are human rights. No nazi bullsh*t.

No thanks. This is DOA.

Minor 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)

I 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.

I'm the author of the quote at the top of this blog post. I've at this point taught rust as a first language to over 400 people and am very amused by the claims in this thread and it's comments. After a few years of doing this I'm not just convinced it's possible, but have seen a lot of evidence of it working pretty well.
> 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.

Another 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.
Anyone 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.

I'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.

> intellectually dishonest

Your claim here is that the author's argument is intentionally misleading. That's an awfully strong accusation, and you don't support it in your comment.

You're also immediately undermining your own argument when you go on to list difficulties in rust that javascript doesn't have.

I 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.
Having 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.
EDIT: 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.

> 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

So 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.

The 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.

I 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/

I 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.