Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Rust Criticism from a Rustacean (codeberg.page)
55 points by nikbackm on June 8, 2023 | hide | past | favorite | 123 comments


When it comes to linking against the kernel, it is worth remembering that of the major operating systems, there is but one where the stable kernel interface is the syscalls directly--Linux. If you use Windows, the stable interface is linking against kernel32. If you use Darwin or the BSDs, your stable interface is libc (and for some of them, there's no stable ABI, only a stable C API). Note that Go has given up trying to avoid using libc on these systems, which should be a sign of how fantastical the idea of a pure, non-C system is for the foreseeable future.


ACK, calling libc is a feature, not a bug. I don't understand this obsession with trying to make direct syscalls for everything. The Redox example ("The Redox project had to write their own libc, in Rust, in order to solve that chicken and egg problem.") is pretty weird too — you're writing your own OS, how is this a chicken and egg problem? My expectation would've been to write a custom "std" regardless? There's some misunderstanding buried there somewhere…


You don't need stable syscalls. Instead of exposing libc as a dynamic library with a questionable ABI, make a stable ABI and expose interface files that contain function names and parameters. You can easily parse these files and generate code for any language to interface with the system.

You can do this with syscalls, you can do this with dynamic libraries, or you can do it with IPC. The point is that it's completely language agnostic and not a pain to parse and use.


The stable ABI for all the major OSes at this point is expressed in C, or put another way, C is the language of FFIs at the moment. This is not something I am happy with, and I wish we could start moving away from it, but the result is that the way you describe the ABI of your OS right now is to provide a C header file containing function prototypes and structure definitions.

In principle, it's also worth pointing out that libc is really three separate (conceptual) things. There's libsyscall, which is the bare wrapper around system calls; there's libuss, OS services provided entirely in userspace and not the kernel (dynamic linking and some aspects of threading come to mind here); and finally, libcrt, which is the actual C runtime that implements the C standard library (e.g., fopen). It's really unfortunate that on most OSes, all of these are combined into one library called libc, although Windows actually separates these into different libraries (ntdll, which is not stable; kernel32-ish, which is stable; and msvcrt, which you have historically had to ship yourself!).


I agree with you completely. And a bigger annoyance than generating headers is actually reading them; C is really not a pleasant format to parse.


Did Redox literally have to write their own libc? With the exact libc symbols and semantics?

If so, that is a bit of a shame. But the solution is to introduce an abstraction layer on top of libc in the stdlib, so there could be a Redox implementation that doesn't have to imitate libc.


> But the solution is to introduce an abstraction layer on top of libc in the stdlib

Which stdlib? Redox isn't trying to only run Rust programs.


Note winapi is the only widely adopted stable cross-platform api. They’ve clearly done something right.

It took a while to implement it on non-Windows oses, but that reality is now here: if you want to run an executable on basically any modern OS and hardware, use the win64 build.


It's really unfortunate. I've crowed about this before. The syscall interface on Darwin is so close to being stable. Even though it's not officially supported (TM), the UNIX syscalls basically don't change. (Only one needless breaking change that I recall in the past 10 years on x86).

We need to shake the C demon and the only way is to push back on kernel ABIs changing.

Virgil doesn't depend on C and runs happily on Linux and Darwin. And yea, I know, MacOS breaks.


There is no C demon. The OS ABI is (de facto — please spare the de jure nitpickery) a bunch of symbols you can call and a calling convention for them. You call into that ABI. What language is used to implement the other side of that ABI is irrelevant.

The fact that this ABI is called "libc" doesn't really mean a whole lot. Neither is the fact that the same library contains a whole bunch of functions primarily useful to programs written in C.


Libc isn't just an ABI, it's a library - one that relies on an opinionated runtime. That's the demon, it's incidental complexity that has been ossified by past design decisions. There is no fundamental reason that interacting with an OS has to require anything more than the minimum necessary to transfer data to/from the kernel (e.g. supervisor trap instruction).


IOCTLs have been broken between major versions before. And by broken, a field has been added to a struct.


And?...

If the IOCTLs are different, then you compile a different binary. What's the big deal? Rust is a compiled language after all.


The worst thing about Rust is easily the community - lots of drama and arguments, people building their personalities about something trivial like which programming language they use because it makes them feel superior, and many fans of Rust refusing to listen to any criticism of the language. It's a designed-by-committe language with a cult around it which might be the worst possible combo.

The second worst thing is how difficult to use it is which makes it not worth it for problems where you can use a higher-level garbage-collected language.


Having participated in Rust for the last 8 years, the community has been great. Very friendly at meetups, always eager to help debug issues or explain things. As an outsider maybe it looks like there's lots of drama but that's not accurate at all. Most everyone I've interacted is very humble.

I always find it ironic that people say that Rust can't handle criticism when it is constantly being criticized... like in literally this exact post that we're all commenting on. That is a happy Rust user criticizing the language lol but yeah sure "many fans" refuse to listen to criticism.


You're right, it's a bit more nuanced. People I've met at Rust meetups have been great, and some of the prominent people in the community are wonderful (I really like Jon Gjengset's youtube streams for example). At the same time if you look at Rust discussions on twitter and reddit, I think they very often match what I'm describing. Sure, maybe twitter and reddit as platforms encourage some unhealthy patterns but twitter/reddit discussions for other languages aren't nearly as toxic as Rust's. So I still think there's something there.


IMO that's just Twitter being a hyper inflammatory platform. Rust's community is also a lot more active online/on Twitter than other languages, so I think that'll bias things considerably.


> on twitter and reddit

There, this was your mistake. :p


I explained why "twitter and reddit bad" isn't a good enough argument.


FWIW, I have seen some of this behavior from people who have just discovered Rust, but none from people who are actually established members of the Rust community. In my personal experience, the Rust community is very welcoming, extremely open to criticism and discussing tradeoffs – and yes, pretty happy of the language, just as every PL community.


I've said it before, and I'll say it again: the problem with Rust right now is that it is in the unfortunate position of being an ascendant language for "cool kids". It has captured some portion of the attention of a younger and more trend-focused audience, and people are attaching their egos and careers to it and jostling to make themselves "known" in its community, etc.

That and some of the projects and types of work adopting it; last year the "web3" and "crypto" companies began piling in, which had a markedly corrosive effect on the language and its emphasis. In general, the amount of "webscale" type work being done in Rust right now has shifted the focus in published crates, etc. from "systems" type work to a lot of the "async serving" types of stuff. For someone like myself whose interest (and day job) in Rust is in embedded, "systems" (closer to the metal, storage, virtual machine, database internals, etc), and the like, this is a bit discouraging. In general the list of speakers at RustCon (before the whole fiasco) didn't look on the whole like the list of speakers around a "systems programming language" for example (with some exceptions).

As more "boring" work is done in Rust, this will hopefully shift. The trend hoppers will move on.


> In general, the amount of "webscale" type work being done in Rust right now

This had nothing to do with web3 and crypto, and everything to do with FAANGs and similar large companies not in those industries.


I don't see that at all. I can't speak for Meta, but I just came from Google last year... there was zero zero zero work being done in Rust for anything service or web related. The only Rust work at Google that I knew of was Fuchsia stuff.

But there's job postings all over the place for either "web3" companies and/or others for tokio/async/web stuff in Rust. Which seems like gratuitous novelty seeking to me, TBH.


Yeah, in terms of "who is using Rust the most" inside of literal FAANG, least to most:

* Netflix isn't using it at all, as far as I know

* Google is using it in Fuchsia and Android, but I'm not aware of many web service things. Fucsia does use async/await though. Not sure about Android as I haven't examined it closely.

* Apple is using it as the backend of services, and on some storage team, though for the latter I haven't heard from it in a while. They're absolutely async/await users.

* Facebook/Meta are using it in a number of ways, for services but also as well as like, the SCM, filesystem, and build system. The latter aren't web services but do use async/await.

* Amazon is using it heavily inside of AWS. You don't get more "web services" than that.

But also, I meant "FAANG" in a broader sense. Large, established tech companies. Cloudflare, Microsoft, stuff like that. If you check out who is sponsoring the Rust foundation (not that that means that this gets you more weight for new features, mind you) https://foundation.rust-lang.org/members/ it's very much not dominated by crypto or web3.

When I was on the Rust team, we didn't prioritize web3/crypto use cases, and I haven't seen any evidence of that changing. It's always been kinda awkward, frankly.

After writing this comment, I also wonder if maybe that's also not some of the disconnect here: while async/await is critical for network services in Rust, it's also useful for other things too. So you have a larger coalition than you may think that's interested in directing the language in that way.


I won't comment on the drama but I don't see a second worst thing. I feel like Rust makes the costs clear and you should* not use it in situations where a higher-level garbage collected language can work.


There are teams rewriting web apps and APIs in Rust. Maybe they're making a mistake, maybe they're doing great and are happy trading off some developer time and training overhead for what they're getting from the language - I don't know which one is more common but the trend of rewriting in Rust is definitely there and it's accelerating.


I'm sure they'll have some success. But if I was the engineering manager or technical lead for teams like this, I would be cautious. From a hiring/staffing point of view it is foolish and probably unnecessary; there is a large pool of talent trained in existing web framework tech, and generally most web applications do not need the latency guarantees that come with a non-GC language like Rust. If you're trying to staff and maintain a team doing this kind of thing, picking boring old TypeScript and staffing up with excellent senior engineers and just applying rigorous quality controls and engineering standards to the codebase makes more sense. It gives you better ability to bring on new staff, and to use existing frameworks.

FWIW I worked in ad serving for some years (at Google and prior) and much of that work is done in C++ because of millisecond granularity P99, etc. latency concerns. Rust is a natural fit there, even though that is nominally "web serving"; but that's a different domain than serving up database-backed microservices for typical web customer workloads; that stuff is on the whole I/O blocked and not impacted by GC sweeps.


> There are teams rewriting web apps and APIs in Rust.

That is not a bad sing, in fact.

That mean the app was write and now is the second(third...) time.

I do this, for work. People pay me to make this stuff several times in the past. And moving langs and other major changes (like move from web to mobile).

Rust make this much better than before: You get some fast, yeah, some safety, great, but much better modeling of logic and great tooling, even errors are much better here! (ie more detailed, better resolutions).

---

Rewriting a system is assumed to be a terrible mistake, and that is true mostly for organizational or political reason, but is VERY profitable if done by technical reasons!

To make it a failure:

- You need something dysfunctional in the org/team, and stay or move anyway will lead to doom. Make the jump to Rust WILL make this more evident!

- You have inexperienced people doing this. Stay or move anyway will lead to doom, but move will be faster!

To make it a success:

- You somehow have a decent org/team

- Budget the time required to make the change, not do it with major time presures

- Do some small test validations, maybe just experiment a little a few weeks/months if the app is truly big.

- Make the jump and use real data ASAP

The rest is obvious work...


Mostly, they are making a mistake. Some people are writing APIs where they genuinely need Rust's efficiency, but not many. I don't think the language of the project team can be blamed for encouraging this, but the community has unfortunately normalised it.


Frankly, I've just moved from writing web APIs in Rust to writing web APIs in Python and I miss Rust. I didn't use the language because it was fast (that was a nice side-benefit) but because it was reliable.


If you have a compute-intensive app that benefits from Rust, it's really convenient to be able to easily add a web interface on it, for stuff like Prometheus metrics and for easy RPC control.


> Your systems programming language should be capable of interop with other languages but probably shouldn't require calling into C just to provide full functionality, such as interacting with the kernel.

Why tho? Like, that's how C and C++ do it, right?

> All you can do is live with it and realize that if you are that low on memory, the OS is likely going to be killing processes anyway. That said, I don't like the way Rust is inconsistent here. Rust normally enforces correctness, yet turns around and treats memory as an inexhaustible resource, ignoring or handicapping a lot of potential use cases for the language.

I think it would be more accurate to say that this is an issue of the standard library, not the language. And it's true, if you want to write certain types of software you need to throw away std.

> You can, at least in this particular case, have your cake and eat it, too.

Emphasis on "in this particular case" ? "Macros are a mistake" is a very broad, sweeping statement. I think it would be more accurate to say "Macros should not be a replacement for other forms of metaprogramming".

Having a native, supported language for compile time reflection is a powerful thing. If Rust one day gets it, that will be cool. I don't think macros are going to be a mistake on that day, they have gotten us extremely far at a very low implementation cost.]

> But at this point I just don't see anyone realistically switching to a std-2.0.

Well, to be fair, I think the vast majority of developers using Rust do not care about linking to libc or handling allocation errors and actually prefer things this way.

I agree that comptime would be cool. Personally, I don't think I'd want the other changes - I definitely prefer Rust stays on Github, for example.


> Well, to be fair, I think the vast majority of developers using Rust do not care about linking to libc or handling allocation errors and actually prefer things this way.

I’d say it’s about the deceptive marketing. Rust is talked about as a safe systems language. I don’t think I’ve ever seen it followed by a disclaimer that this only applies to systems with unlimited memory.

It doesn’t of course stop at the marketing slogan. Problems like these aren’t sufficiently promoted in the documentation either.

I think that being more open about these problems would help enable a solution.


Rust is a "memory safe" systems programming language. That has a specific meaning which does not include the method of allocation failure handling.

I would bet money that the majority of C code doesn't check the return code from malloc. What Rust does is strictly better than that. For people that do care, the APIs for fallible allocation are being added over time.


> I would bet money that the majority of C code doesn't check the return code from malloc.

There's a difference between "I was trying to load this 1 pixel = 1mm scale image of central Paris into memory but I don't have 1.3TB of RAM" and "Allocating 4kB of RAM to grow my Vec was impossible". In the latter case you are definitely screwed, and Rust's choice here is fine, any imagined recovery is a fantasy, somewhere something else will also need some RAM and it'll blow up and everything is on fire, aborting now was the right choice unless you're a space probe or something (in which case you should have not been written to go around dynamically allocating memory all over the place)

In the former case it'd be nice to notice OK, that's unreasonable, I don't have that kind of RAM so we shouldn't attempt this. But, wait, is it OK to allocate say, all remaining RAM except 16kB? That wouldn't strictly fail but it sounds like a bad idea too. So maybe we actually want a configurable limit. It might be reasonable to say for example, we're an image loader, we will by default allow up to 50% of our RAM to be image data, in the same way that many thread pools assume it's OK to have about N threads if you have N CPU cores by default.


> In the latter case you are definitely screwed

No, you're not. You just have to handle the case of not having heap memory to spare. If you were out of _stack_ space, now that's being screwed.

> and Rust's choice here is fine

Of course it's fine - for a language that doesn't claim to be safe. So, for Rust, it is not fine.

> any imagined recovery is a fantasy

That is the attitude of people who write non-critical applications where it's ok to be lazy and just let the process die and restart things.

It is not fantasy, it is not imaginary, and it is quite doable (except in corner cases of tiny machines for which 4 KB is a lot, in which case you would probably not do dynamic memory management on a heap anyway).


> You just have to handle the case of not having heap memory to spare

You have to successfully handle this case. Rust already handles this case by panicking, which you've unilaterally decided isn't safe for some reason. If that's not good enough you need to succeed. You must conjure the 4kB from nowhere. Show us all how it's done, or, and this might be the better choice, slink away to your fantasy land.

You are right at the end though, if you can't accept that running out of memory might happen what you do about that isn't dream up miraculous ways to "handle" it, you don't do dynamic allocations. Which of course works just fine in Rust.


Dynamic allocations work fine in a memory constrained environment. Successful handling can mean just postponing a task. [1] You just have to build your app in a way where there is a core that can continue running with no further allocations.

Chrome is a decent example. Some of its processes might crash in an out-of-memory situation, but that only causes some tabs to lose their display state. The browser as a whole keeps running just fine. A similar solution can be done within a single process too.

--

[1] By task I mean some app specific unit of work that makes sense, not some Rust std lib string allocation.


> [1] By task I mean some app specific unit of work that makes sense, not some Rust std lib string allocation.

Congratulations on successfully moving the goalposts. You don't get to decide which dynamic allocations fail, if you did obviously you'd choose "none of them".

> You just have to build your app in a way where there is a core that can continue running with no further allocations.

Again Rust - unlike say C++ - is actually defined so that this just works. So whereas C++ std::array can't exist in the standard without also having a heap allocator - yes really, Rust's [T; N] works just fine even including fancy features like select_nth_unstable_by_key() without needing an allocator.


> I don’t think I’ve ever seen it followed by a disclaimer that this only applies to systems with unlimited memory.

So, a Turing machine?

Why Rust doesn't prevent memory leaks - answer is simple. It's too much pain for modicum of gain.

People crow about lifetime being hard, now imagine how much people would complain if you add another orthogonal system to track memory allocation.


You couldn't meaningfully "prevent memory leaks", and that's what Rust's Leakpocalypse was about.

Suppose I have decided to model marriage. My Person type has a spouse: Option<Rc<Person>> and when you marry() another Person it fills out both spouse references. Now I make Bob and Alice, and marry them off, so Alice contains a reference to Bob, while Bob has a reference to Alice. Romantic. Next, I throw away my only Alice reference, but that's OK, I have a Bob, and Bob has a spouse field with a reference to Alice, so Alice isn't destroyed. Then I throw away Bob, likewise Alice has a reference to Bob, so Bob isn't destroyed either.

I have now leaked two Persons. I have no way to get them back but they exist forever (well, until program termination).


I can't tell whether the author doesn't know, or is pretending to have no idea, that most systems do not offer a stable system call ABI.

Windows is the most obvious example. Microsoft does not officially document most of their system calls, and makes no promises that they work how you think they do/ how your unofficial documentation claims they do, or that what worked yesterday will keep working, the official documented APIs are to userspace code that you didn't write.

But this is also common on the other Unix systems besides Linux. You define the libc API as what you're promising and then you deliver or don't deliver features in your syscall ABI and the libc handles the slack.


Coming from outside, the take on macros resonates. Working with modern 'Rust' The Language is rather nice. But when one of my first main projects was to add support for a serialization format with Serde, running into macros feels like running into a wall. It's a whole next level of complexity and poor tooling support (at least at the time).

Granted, I've had similar feelings about C++'s template shenanigans, so take it with a grain of salt. Zig's comptime feels like a breath of fresh air in comparison.


Adding serialization with serde is a matter of adding `#[derive(Serialize, Deserialize)]`. I guess that's magical in a way, but does that matter?


GP is talking about adding support for a specific format to Serde, something equivalent to serde_json, not serializing an ADT they have. I've also found it to be difficult.


Ohhhh, I see. Yes, I think comptime would be a big win there.


The article skips directly from #4 to #6, so I'll nominate something for #5: ranges should not be iterators. Instead they should impl IntoIterator and the iterators should be separate types. That way ranges can impl Copy without any issues. https://kaylynn.gay/blog/post/rust_ranges_and_suffering


It's a well known issue, but it might never be solved due to backwards compatibility. They were made non-Copy to avoid a nasty footgun, and way before IntoIterator existed.


Not a Rust user, so not some intelligent criticism... but boy how Rust source codes hurt my eyes ! Things like this:

    <'_>
    #[]
    stuff::thing::blah
    @gloop(gloop)
    if(fizz) |buzz|
    .Meh => |wtf|
I know, I know... you probably get used to it once you understand the semantics and it's subjective anyway and and and... but still, not all languages I know repel me visually.


The last three are taken from the OPs Zig example, and is not valid Rust at all.


Oh ? Thanks, fine... so that applies to zig has well...


Despite the invalid example, the point still stands. Put arbitrary Rust against Python or Typescript and you'll see it immediately.

I love Rust and very much like OP it comes very close to my ideal language. I also think it had very good start when it comes to syntax but did a wrong turn when it copied things from C/C++, which in my opinion have horrible syntax for mostly historical and obsolete reasons.

But not all is lost. With the editions mechanism we could do a syntax overhaul. I really, really hope that will happen.

Meanwhile it's the small things everyone can do. One thing I advocate for is to adopt the most common style for identifiers in Java, Javascript, Typescript, Python, and even some parts of the C/C++ world and do away with snake_case.

If we could do away with underscores and double colons we could have a much nicer language already.


What is better about Rust vs Python's syntax?

    struct Foo<T> {
       t: T
    }
vs (assuming we get the pep for inline typevars)

    class Foo[T]:
        t: T
I don't see how Python is meaningfully better at all.

Or

    use foo::bar::baz;
vs

    import foo.bar.baz
I just don't get the problem here. "double colons bad" is just an extremely subjective take that I don't really buy at all. I much, much prefer snake case and would hate to see pascalcase in Rust, but also at the end of the day these are such minor things that barely barely impact readability.


> "double colons bad" is just an extremely subjective take that I don't really buy at all.

It is objectively worse to type shift+; two times than a single non-shifted period.

That's a very simple selling point, what's there not to get?


What I find worse than the typing issue (which I agree with) is that it is an uncommon choice for something a very common choice exists.

Even worse is that its use is so similar to the situations where the dot is used that it's just confusing. The Internet is full of questions when to use which. This is in my eyes unnecessary complexity and does not mesh well with the aspiration of Rust wanting to be beginner friendly.


FWIW I am "pro-dot". I just don't think it matters much at all.


    struct Foo<T> {
       t: T
        }
Braces... one extra sign (and line) for nothing while indentation works fine.

    import foo::bar::baz;
    import foo.bar.baz
4 times the dots, also useless comma.

Objectively less visual noise in Python. Of course the importance of it is subjective, I agree with that. But still, less cruft is good.

> minor things that barely barely impact readability

Of course, I don't agree :-)


These are subjective things. I don't consider Rust syntax perfect, but I don't these suggestions as way to improve it substationally.

If you want to get rid of `::` and `;` and braces you have to look at the fallout of those decisions.

Braces are imo much better at being robust than whitespace.

    def Foo[T]:
      t: T
      size: u32 // invisible error here because someone used tabs by mistake

`;` disambiguate expression vs statement. If you remove it you need way to differentiate between them.

Another problem with `import foo.bar.baz` is how will you distinguish between a method call or a type declaration? E.g. `std.option.Option.Some` what is this? Type? Method? Module? What is `std::f64::consts`???

Not to mention you kinda have to have compiler in mind, if syntax is ambigous you're going to have a very bad time.


I agree with that and would not want to see braces and semicolons go because they are pretty conventional. In this case Python and Javascript/Typescript are the outliers.

It's the opposite for the double colon syntax which, apart from Rust, to the best of my knowledge only exists in C++ (for good reasons) and some functional languages for a completely different purpose.

Honestly curious question: What fallout would you see from replacing it with a dot in Rust. I immediately see no disambiguation issues, but I'm not a compiler writer.


> // invisible error here because someone used tabs by mistake

would not parse, so no invisible mistake.


Implying every site you post code to will have correct syntax highlighter.


Rust's philosophy is "explicit over implicit" - braces fall inline with that. One extra line for a struct is really not a lot.

That whitespace sensitivity also leads to having to escape newlines, with `\` trailing lines all over the place in Python. I find that far uglier than "4 times the dots" for import statements.

> Of course, I don't agree :-)

For sure, I think that's kind of my point. Like, this all feels very unimportant to me and extremely subjective. I think that rust's syntax fits into its philosophy, however. I would not mind unifying path syntax such that `:` became `.` however.


oh the irony...

    "Explicit is better than implicit."
;-)


It's a fantastic example of how witty sayings don't necessarily lead to agreement, even among people who would agree in the truth of the saying.


Indeed... "philosophy" is often a poor justification for technical choices.


I don't actually see the irony?


> Despite the invalid example, the point still stands. Put arbitrary Rust against Python or Typescript and you'll see it immediately.

Eh, I don't think that is fair, Rust even at best of times will have concepts like lifetime/references that Python and TS can just ignore and are thus "simpler".

A much better comparison would be something like https://matklad.github.io/2023/01/26/rusts-ugly-syntax.html.

> and do away with snake_case.

That's seem counterproductive - according to: http://www.cs.kent.edu/~jmaletic/papers/ICPC2010-CamelCaseUn....

I.e. you would do with most readable part of syntax.


Before Rust everybody[1] seemed to believe we cannot have a safe and natively compiled language. Rust proved the opposite.

I don't see why we can't have clean, low noise, high signal syntax in a language like Rust. My criticism is not the syntax that makes the language more expressive - that's essential complexity.

I would want the accidental complexity removed, like the somewhat redundant distinction between dot and double colon. And I wish the cognitive load reduced by making the syntax as familiar as possible to as many people as possible. That's the reason I mentioned Javascript and Python - not only is their syntax more concise but also familiar to more people.

When it comes to the snake case study, I'm not surprised at all. They did not control for the size each identifier took on the screen. That a bigger signal enables a faster response is common sense. Longer identifiers are easier to recognize but the downside is that they take away space we could use for other important things. That's why most languages keep the most frequent ones (like variable names) short and free from unnecessary noise like underscores. Also the sample size in the study was extremely small.

[1] Except the Haskell/ML folks, naturally.


> I don't see why we can't have clean, low noise, high signal syntax in a language like Rust. My criticism is not the syntax that makes the language more expressive - that's essential complexity.

As I pointed in Matklad's post you need to add those concepts in or devise a way to infer them, side by side comparisson of Rust/JS is meaningless if one has no concept of lifetime or one abstracts details via GC.

> Before Rust everybody[1] seemed to believe we cannot have a safe and natively compiled language.

I do agree, but you can't avoid all trade-offs. Rust got safe, natively compiled language by increasing type complexity (adding lifetimes and ownership), and adding more sigil noise. If Rust had GC it would be way simpler and way less usefull.

> like the somewhat redundant distinction between dot and double colon

I don't think it's redundant. But I'm not a Rust compiler guy.


> Meanwhile it's the small things everyone can do. One thing I advocate for is to adopt the most common style for identifiers in Java, Javascript, Typescript, Python, and even some parts of the C/C++ world and do away with snake_case.

snake_case is used a lot in Python:

    module_name, package_name, ClassName, method_name, ExceptionName, function_name, GLOBAL_CONSTANT_NAME, global_var_name, instance_var_name, function_parameter_name, local_var_name.
(not mandatory, it's just from the style guide)

But I don't even think snake_case or CamelCase matter as much as plain keywords vs. symbols or "commonly used" symbols and ones that are not too noisy.

I know compared to Rust strong points this all seems to be petty criticism, but we all read lots of code, probably more so than writing.


I'm OK with SCREAMING_SNAKE_CASE for constants, because that is an ubiquitous convention. Same for globals, they should be rare anyways (and constant most of the times). For crates dashes are already widely used and that is how it should be.

+1 for plain keywords. Common separators when necessary (e.g. constants or everything that ends up in the filesystem, bc upper/lowercase is a pain there).

Regular struct, enum, trait variable names: CamelCase hands down, like almost everyone does it.


Variable names in most languages are pascalCase, not CamelCase, which is typically used for type names.


Your last three examples are syntactically invalid Rust. It should be more like:

  <'_>
  #[foo]
  stuff::thing::blah
  match gloop(gloop) { x @ _ => x }
  if fizz { |buzz| Some(buzz) } else { |_| None }
  Meh => |wtf| ()


You're certainly right, I just copy/pasted stuff from the article and changed identifiers, probably adding errors in the process, but the point was never to give accurate examples, just point that even reading Rust code requires significantly more learning than other languages. YMMV of course.

Thanks for correcting me. Still not a joy to read though.


It requires less learning than Haskell. A tad more than C. Less than C++.


> Less than C++

That depends. Rust requires less learning than C++ for writing safe code. There are plenty of C++ developers that feel like they know the language but produce unsafe code. Rust won't let you do that, so these developers complain.


Interesting article, but:

> Then there's the issue that the crates.io registry is on GitHub, and only GitHub, and in order to publish on crates.io you have to have a GitHub account

This isn’t true. Crates.io publishes metadata to a GitHub repo, but that’s decoupled from them only supporting Github as a SSO.


The point is that if you want to publish a crate to crates.io, you need a GitHub account, which is true and verifiable in ten seconds. Not sure why it's important how it's required, the end result is the same.


You’re commenting on a site that is fairly well known for being pedantic.

> Then there's the issue that the crates.io registry is on GitHub, and only GitHub

There are a number of issues with this. The public crates registry is available in sanctioned countries, and it’s not even used by default anymore.

This is independent of crates.io only supporting GitHub as a sign-up option. People from sanctioned countries can also sign up for GitHub accounts, but cannot access private ones or paid membership features.

The author conflates these two issues in a way that confuses the point they are trying to make, which has nothing to do with the crates.io registry being on GitHub or access from sanctioned countries.


Wait, seriously? But GitHub is a censored platform, it's not universally accessible. Microsoft is blocking people from US-sanctioned world states:

https://techcrunch.com/2019/07/29/github-ban-sanctioned-coun...

how can Rust conduct any official business on such a platform?


I am surprised that you are surprised that Rust is relying on GitHub. Hundreds (thousands probably?) of companies use GitHub to host their code and daily business operations, including Rust


Rust Foundation is a US-based organization so it has to follow its declared goals and principles only to the extent that the US laws allow it, you know?


1. Don't know that there's anything preventing US-based organizations to use non-US-based computing platforms which are universally accessible. And if things are indeed that bad - that means Rust as a project has decided to define itself as a partisan US endeavor. USers might hear this and just shrug carelessly, but imagine how you would feel if the Rust foundation's websites would be inaccessible for people in, oh, say, New Jersey. Nobody from Jersey could publish rust crates. That's preposterous.

2. The UN's headquarters are in the US, the same principles should apply, although I realize legally that might not be the case. Then again - maybe projects like a programming language should actually be constituted via the UN, or ISO, to have the appropriate non-partisan legal basis for operations.


> there's anything preventing US-based organizations to use non-US-based computing platforms which are universally accessible

Trade/technology embargoes and sanction regimes are just such things. For an example how arbitrary those can be, the US sanctioned a German port for participating in NordStream 2 construction — and that project had zilch to do with the US, even its financing was done in Euro, not USD.

> The UN's headquarters are in the US,

And the US somewhat regularly declines its visas to the UN representatives it doesn't particularly like. So?

In any case, an international organization (and its members) is not automatically outside of the jurisdictions of the country (countries) it's physically in; if such a need arises, the governments have to pass specific laws regarding those specific organizations and its members, granting some sort of immunity or another. Or they just don't, and the organization simple has to function as a non-profit multinational.


Easily and with great success?


Rather successfully apparently. Maybe you’re overestimating the number of would-be contributors from sanctioned countries who aren’t using workarounds?


You realize this is a self-fulfilling prophecy. If people from certain countries are excluded - formally, technically or culturally - naturally they would not tend to even try to contribute.


> ...I'm actually looking for "the next language" to come after [Rust].

It would really be a better approach to work on getting Rust to adopt the features of Zig you're looking for. The work it goes into developing a language into a mature option is absolutely massive. Developing a full-featured language, building a (healthy) community around it, building dev mindshare/marketshare, building trust that it's sustainable, etc is a many-years effort by many talented and dedicated people. It's a huge amount of work when you could achieve the same output by adding a certain feature or two to rust.

Of course the leadership is a bit broken right now, but they may (or may not) be able to fix it.

There's also the Typescript approach. That is, extend rust with a comptime feature wrapper. Not nearly as elegant, but you don't need to work with broken rust leadership to develop it and, if it gains traction, you may then have the leverage to get it rolled in to the real thing (if you even want to at that point).


> It would really be a better approach to work on getting Rust to adopt the features of Zig you're looking for.

I was just pondering the other day about how nice it would be to take to get the same level of quality C/C++ integration that Zig has, but in Rust. My new job has acres and acres of C++ which isn't going to go away. Linking and wrapping against C++ is one thing; build system integration is another. Zig has some serious advantages there.

That and I really want allocator_api and simd to get into stable.


What are the limitations you encounter with cxx and auto-cxx?


They're totally orthogonal from the huge win here, which is how zig cc embeds clang, includes libc headers, etc.


I'm not familiar with Rust vs Zig C++ integration.

What are the stumbling blocks? Lack of stable ABI in Rust?


I don't have much Zig experience at all, but from what I've read Zig is pretty genius because in addition to being a Zig compiler -- with its own sane build system -- the same tool also acts as a C/C++ compiler.

So mixing Zig and C/C++ has a lot less friction.


I seem to remember a Rust toolchain that actually uses Zig as its cross-compiler (I think).

Would that help?


> "The concept of generics is only possible with some sort of compile time reflection in any language"

This is not true.

* The standard implementation technique is to box everything (have a uniform in-memory representation for all types). Monomorphization[1], which is the compilation strategy used by Rust, C++, and I guess Zig, requires type knowledge at compile-time.

* Generic functions should not have any knowledge of the concrete types of the values they are passed, as this breaks an abstraction boundary. Theorems for free[2] is about this idea.

[1]: https://en.wikipedia.org/wiki/Monomorphization

[2]: https://www2.cs.sfu.ca/CourseCentral/831/burton/Notes/July14...


How can you call a method on a type if you don't know anything about it ? How do you even know the method exist without some dynamic casting of sorts ?


It's not calling methods on a type that is the issue. It's passing parameters to a method or function when that method or function has a generic type for that parameter.

In Rust this is something like

    fn foo<A>(a: A): A
(which can only have one implementation, the identity, if you don't break the abstraction barrier provided by generic types.)


You pass that method along with the value, so it's the caller's responsibility. At some point along the call stack there will be a monomorphic function which has to know the actual type it's calling its polymorphic callee with.


> In the meantime, you can and should use Rust. In spite of any shortcomings it's still the best language that has come so far in terms of enforcing memory access safety and overall correctness

1. I don't think programming languages can "enforce correctness". (Although I will say that my general experience is that functional languages, not Rust, tend make it more difficult to get things trivially incorrect.)

2. I'm not sure that's a good enough reason to use Rust. I mean, sure, Rust is usable, people do things with it, but - my biased experience is that at some point you just go C++ for some reason, and stay there.


As an avid rust proc macro crate author, the zig macro example is quite humbling. I would welcome this kind of reflection and comptime stuff in place of (or more likely, in addition to) the existing macro systems (decl macros, and proc macros) that we have in rust.

Proc macros are particularly awkward because of the requirement that they must be defined in a separate proc macro crate. There are all sorts of things one could do if it were possible to instead make proc macros that generate proc macros _in place_ like one can with decl macros.

Then there is also the issue of macro expansion... the rustc framers openly admit that with an expression like foo!(bar!(..)) it is often preferable to have bar!(..) expand _before_ foo!(..) expands, because they have hacked in this behavior for several of the built-in macros like `concat!`, however this behavior is completely unavailable for custom macros. In fact, this one little issue is the ONLY blocker to all kinds of exotic and powerful behavior, the lack of which is holding the ecosystem back, for example the ability to eagerly expand a series of macro calls would enable the following things:

* the ability to determine the column, line, and source file in which a macro is being called, at compile-time

* the ability to determine the module path of the caller of your macro, at compile time

* the ability to determine the name of the crate in which a macro is being called, at compile-time

* the ability to implement complex compositional behavior purely in proc macros

* (very important) the ability to determine the `CARGO_MANIFEST_DIR` of the crate in which a macro is being called. Without this key ability, it is impossible to reliably determine where we are executing so we can do things like read metadata configuration values from _the caller's_ `Cargo.toml` at compile-time.

So yeah, really hoping at least eager expansion stabilizes sometime soon, but this zig stuff would be even better.

Some of my crates that would benefit from this:

* docify: https://crates.io/crates/docify

* macro_magic: https://crates.io/crates/macro_magic

* crate-settings (non-functional until this comes out): https://crates.io/crates/crate-settings

* proc-utils: https://crates.io/crates/proc-utils


Comptime on its surface is such a better alternative to macros, the fact that you don't need to learn another DSL is huge (and all the tooling works at is)

Would it be a major challenge to add it to Rust?


For me it is the crates not having something like a namespace.

Something like this: @org/axum @user/axum


"No this is a feature you see, that way people will have to come up with creative names" (that have nothing to do with its task and that nobody can remember, oc) was the standard reply I got when I said as much.

They should have just copied the Maven Central mode of operation, it has matured over many years and works well, without any drama such as NPM is infamous for.


Not really. The Rust community is very well aware of the problem. Not sure when namespacing will become possible, but it seems pretty clear to me that it will happen eventually.


You say this like is some difficult technical challenge to overcome, when that was a very deliberate design decision upfront.


It was. But the problems have emerged. Now it's a liability and the community is thinking about how to improve the situation.


The problem is adding namespaces on at this point seems very hard.


The issue is "but people will just squat namespaces". I don't agree, fwiw, but that's one of the main push backs.


This is easily solved by

1) using registered domains as namespace (if one exists)

2) proving that you have access to said domain

This is how Maven does it and it works very well.


That's not easily solved at all. That's an incredibly complex system you're proposing.

IMO the solution is simpler. Heavily rate limit the creation of namespaces. That's less viable for crate names, but it should be very uncommon to create more than a few namespaces. You could give people a low number that aren't rate limited, like 5, and then rate limit them to 2 a day afterwards.

They can then publish unlimited crates under those namespaces.


which forces people to pay to register a domain just to publish packages...


I don't think that's necessary, since cargo and source repo is tightly linked, just make that source repo supports returning user name or org name.

I don't see a reason you couldn't use exisiting org/username from Github as namespace, can they squat on it? Not unless they steal it, in which case, Github should be notified.


What happens when crates are transferred? Everyone's build breaks.


What do you mean by transferred? Like you have Ygg2/stuff and want it to be replaced by Org/stuff?

In that case just yank all versions on Ygg2/stuff, and the any change update from then on references Org/stuff.


Yes. For example, the semver package has lived in these places:

* rust-lang/semver

* steveklabnik/sevmer

* dtolnay/semver

That everyone didn't need to do "yank everything, change all cargo.tomls" is a huge advantage of not being tied to this.


Well change all future `cargo.toml`s.

If you want a more complex solution, then you would need a more complex index of ownership for cargo. E.g. alias or transfer ownership. It could be as simple as displaying "This crate is deprecated use org/crate instead". Or as complex as what crate is no longer valid.

One needs to know what exactly are cargo namespace requirements?

> Yes. For example, the semver package has lived in these places:

Sure, and squatters squatted over many crate name extorting bribes to release them.


I think Github repos work too.


Yes, common sense like namespace is NOT an easy thing to do for some people.


I think Rust should be bold and stop depending on C for anything. It's gaining enough momentum that eventually it should force kernels to be like Linux and adopt a stable ABI. In practice, most kernels have a "fairly stable" ABI just because coordinating kernel changes with userspace libc changes is tricky.


> It's gaining enough momentum that eventually it should force kernels to be like Linux and adopt a stable ABI.

This both misunderstands the impediments, and wildly overestimates Rust's position. First, on some platforms like OpenBSD, it's not just a matter of stability per-se; OpenBSD implements some of their security measures in libc, and therefore intentionally forces its use. Second... how exactly is rust going to "force", say, Windows, to change how they present the userspace/OS interface?

> In practice, most kernels have a "fairly stable" ABI just because coordinating kernel changes with userspace libc changes is tricky.

I don't know if you're using a loose enough definition of "fairly stable" that it's meaningless, or mistaken outright, but no, at least NT can and does change its syscall interface often enough that it actually prevents people from using it in any meaningful way (read: sure, you can do it as long as you never update, but then the next time you run Windows Update it will break).


That's just not going to happen, and is not even necessarily desirable.


Who's going to tell him that comptime functions is what macros are?


They're not?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: