all 169 comments

[–]robin-m 102 points103 points  (91 children)

I had more or less the same question on the forum recently. I was advised to watch considering rust. You can find the slides and more material in the answers to my post. This conference was a really good watch, and should give you an honest idea of what Rust is. It's not specifically the "bad" part of Rust, but more of an overview, including its defects.

Most of Rust the bads in Rust are:

  • critical library not being 1.0
  • missing features that are currently being worked on (const generics, generics associated types, …)
  • compilation times
  • initial learning curve (unlike C++ once you have learn a lot you will not continue to discover an infinite amount of landmines, but learning Rust isn't easy at the beginning).

If you plan to learn rust (I know it's not your question), I also really like that gives you the key to be able to read rust code in half an hour

[–]MrK_HS 12 points13 points  (3 children)

initial learning curve

I've found learning Rust far easier than C++. In a month, from zero experience, I've been able to become a regular maintainer of a fairly complex ffi based repo.

This is my theory on why it's easier:

  • Documentation is extremely good compared to C++ (cheats.rs has basically everything you would need, and crate docs are usually good). Yes, there are popular C++ books, but they are too long and boring. Online documentation is also generally bad for C++.

  • There aren't a thousand ways to do the same thing (there is only one way to write idiomatic Rust)

  • The compiler helps you in the learning process

By the way, I gave up learning idiomatic C++ because everybody has a different idea of what idiomatic means, ranging from C with classes to weird templating.

[–]robin-m 2 points3 points  (1 child)

I totally agree with you that Rust is easier than C++, but you can't say that Rust easy to learn when there are language like python that exists. I don't consider Rust to be that hard, but I would definitively not call it simple. Rust nearly force you to be a good programmer that write fast, bug-free code (and I love this). However, when learned, those rule become easy to follow, unlike C++ witch has so much more complicated rules for anything you may not expect (and I love C++).

[–]MrK_HS 0 points1 point  (0 children)

I didn't say it's easy in a general sense, but I agree with the rest, especially the fact that it becomes easy to follow after a threshold. It is a very rewarding language in that sense.

[–]dnew 0 points1 point  (0 children)

everybody has a different idea of what idiomatic

I think that's because "idiomatic" changes ever few years as new versions of the spec are released. What's idiomatic this year didn't even exist in the language 2 years ago. (Holds true for Java to a large extent too.)

[–]MrVallentin 30 points31 points  (45 children)

compilation times

I'm working on +40K lines codebase of real-time rendering spread across 6 crates, with inlining and procedural macros that cause 5 of them to get recompiled every time. I just timed a build and it was around ~20 seconds, which I personally consider fast.

Sure, a clean build takes ages, but generally that's a once and done deal. So out of curiosity, what's considered long compilation times?

[–]Ayfid 35 points36 points  (28 children)

There are few languages slower to compile than rust. C++ is one of the few notable examples, and it is infamous for compile = coffee break.

I think the larger issue is not so much compile times, but rather how slow cargo check is. I have a far smaller project than yours which none the less takes ~15s to check, meaning that I need to wait 15s after writing a line before I get any feedback from the compiler. Having to wait 15s in every minute or two certainly is noticeable.

Every other language I use provides that feedback essentially instantly, and most would compile such a project in low single digit seconds.

[–]MarcoGroppo 15 points16 points  (1 child)

I have a far smaller project than yours which none the less takes ~15s to check, meaning that I need to wait 15s after writing a line before I get any feedback from the compiler

The real issue here is that you shouldn't need cargo check to get diagnostics from your editor/IDE. Both the RLS and rust-analyzer currently need to call rustc (via cargo check or save-analysis) to obtain warnings and errors, but in theory they could provide diagnostics in real-time as you type. This is not an easy task, for sure, but to my understanding rustc and rust-analyzer are moving towards this (long-term) goal.

[–]thelights0123 6 points7 points  (0 children)

And that's what IntelliJ does, but as a result, it doesn't catch every error.

[–]LikesToCorrectThings 16 points17 points  (22 children)

You have to remember that those other languages are doing much less for you in terms of checking. A check that says "sure, it's fine" instantly and then the program crashes in production at 2am with NullPointerException is essentially worthless.

[–]Ayfid 17 points18 points  (20 children)

Indeed, but even so things are what they are. When I have to wait for feedback after writing a line, most of the mistakes that are likely to present (e.g. I forgot to change a variable to mut, or haven't imported a type) are things that other language compilers catch too, but they do it without interrupting the work flow whereas with rust I often tab over to reddit or YouTube while I wait.

Also, Rust's compile/check times cannot be wholy credited to increased checks. For example, rustc is still pretty bad at incremental compilation and due to proc macros and monomorphisation it often needs to recompile dependencies where other languages would not.

It is also not as if rustc catches all bugs. Rust programs do still crash at runtime.

[–]LikesToCorrectThings 7 points8 points  (0 children)

True. Perhaps part of the problem is that you have to wait so long to get any feedback at all. If we could get these common checks from earlier phases (syntax errors from the parser, basic type checking) to the user quicker, that would be a much better experience. It might be not so bad that borrow-checker errors only fill in after 15 seconds if the basic syntax and type stuff from earlier phases was faster.

Probably that needs better infrastructure and support from IDEs and the compiler, though.

[–]dnew 1 point2 points  (0 children)

Sounds like "check" needs to be a more optimized for small changes. Like, C# is designed that the insides of functions can all compile in parallel. I would imagine Rust is probably like that too. Changing a "let" type should be able to complain without having to recompile anything outside the function, shouldn't it?

[–]pjmlp 0 points1 point  (0 children)

ML languages are as complex and don't crash with NullPointerException at 2 am.

They just happen to have multiple backends and interpreters available as well.

[–]BB_C 3 points4 points  (1 child)

I have a far smaller project than yours which none the less takes ~15s to check

Something could be seriously wrong at your end.
Are you sure cargo check actually takes that long?
Are you sure IO and/or system load in general is not slowing things down.

If cargo check is indeed taking that long. And nothing is wrong. Then I wonder what kind of code base you have. Maybe overuse/misuse of metaprogramming and/or generics is at play.

[–]Ayfid 7 points8 points  (0 children)

The project makes very heavy use of generics, inlining, and proc macros. Rust is bad at compiling such code and so I get these large compile times. But the project cannot be simply written to avoid this, and rustc taking a long time to compile this code is a flaw with rustc, which is the topic of this thread.

[–]pjmlp 0 points1 point  (0 children)

And for new code bases that might eventually be a thing of the past with C++20 modules.

[–]est31 8 points9 points  (1 child)

  1. 40k is a lot but rustc and servo are in the hundreds of thousands, and a fighter jet has millions of lines.

  2. clean builds are NOT one time things. A single cargo update of a dependency used by many of your deps can cause your entire tree to recompile. Every six weeks there is a new compiler, invalidating your entire cache. And sometimes there are point releases like recently. You can't just pin a compiler version and use it for a year, you are required to follow the community unless you want your dependencies to break.

[–]MrVallentin 1 point2 points  (0 children)

clean builds are NOT one time things

Of course, but the same could be said about e.g. Python. Sure, it doesn't have to compile the dependencies, but it still has to download them.

My point was more, if I had to suffer through a daily cargo check, with many updates, then I'd do it as the first thing after my computer turned on. Then while it's updating I'd check my backlog and think about what's on for the day.

[–]robin-m 20 points21 points  (9 children)

Anything longer than real time analysis of the lines you are currently modifying is long. I'm exagerating a bit, but if you can have instant feedback of what you are working on, it enables you to immediatly fix any mistakes you can while while everything is still in your head. It may not feel important if you never had the opportunity to do it, but once you have tested it, you can't go back (see the blub programmer syndrome). It's like for git, by being so fast, it enabled workflow that could not have been imaginated before.

[–]kixunil 1 point2 points  (1 child)

Fair definition. I personally find direct feedback from type errors very quick and very helpful, so that helps a lot. Once it compiles it mostly works in general, so this effect counter-balances decreased efficiency of integration tests/manual testing, I think.

Lately, I suffered a much longer loop: * Change something in Rust program, which is a code generator * Copy it to a different VM * Recompile * Regenerate the other code * Rebuild * Spawn another VM to test

That is pretty insane and I already recognize the things I need to do to resolve it and keep my sanity. :)

[–]SafariMonkey 0 points1 point  (0 children)

Any time I have to repeat a process like that I make it a make target. It doesn't have to be make, but it sounds like some kind of automation should help.

[–]LegitimateChard 1 point2 points  (5 children)

You were using rust-analyzer, correct? That's basically real-time.

[–]Ayfid 4 points5 points  (4 children)

rust-analyzer picks up some things (like type hints) quickly enough, but it still has to rely on cargo check for most errors and warnings.

[–]LegitimateChard 4 points5 points  (3 children)

Fair enough.

I come from C# with its sub-10 second build times for collosal projects. I built my code hundreds of times a day. I don't miss hitting that build key at all and feel significantly more productive (and rewarded).

Each to their own. They are constantly trying to improve Rust compilation times, but I don't think it will ever be as fast as you want. Something like C# will always be faster to compile because it defers a lot of work to runtime.

[–]pjmlp 0 points1 point  (1 child)

Except C# also AOT compiles to native code, so it doesn't always defer to runtime.

Same applies to F#, just to be a bit more closer to Rust in expressiveness.

[–]LegitimateChard -1 points0 points  (0 children)

so it doesn't always defer to runtime.

Generating native code is only a small part of why Rust is computationally expensive to compile - are you intentionally misrepresenting that?

Edit: you spend an huge amount on a sub about a language that you clearly despise.

[–]dnew -1 points0 points  (0 children)

C# was designed to compile fast. It's designed that what's inside a function can't affect what's outside that function at compile time. So you can scan the source to find all the declarations, then compile each method in parallel, which is why you can compile the code three times in a row and get three different object files.

Rust could probably be like that, as long as you're analyzing something that only changed the inside of one function since the last analysis, but there might be stumbling blocks I'm not noticing off the top of my head.

[–]NietzscheMustacheCum 6 points7 points  (0 children)

Reminder that cargo check exists.

I feel the same. My monitor (someone) takes 15 seconds to leave sleep, so 5 seconds is still really fast for me. Then again I've never written an actual C/C++ project.

[–]pjmlp 1 point2 points  (1 child)

Thing is, even with C++ a clean build might be faster than Rust, because most people use binary dependencies, so a clean build only includes their own code.

[–]dnew 0 points1 point  (0 children)

Sounds like an option to build using cached crate binaries might be a good idea.

[–]davidw_- 0 points1 point  (0 children)

you're lucky, my project takes like 20minutes to build in debug mode : D

[–]dpc_22 4 points5 points  (39 children)

I don't see why not being 1.0 is a problem. There are many libs out there which gave a stable API and most libs follow semver guarantees to not be a concern for the user

[–]masklinn 52 points53 points  (20 children)

I don't see why not being 1.0 is a problem.

It's a problem for critical libraries as it means core parts of the ecosystem are potentially shifting sands, yet get used pretty much by necessity.

[–]nbsdx 20 points21 points  (19 children)

We're about to start a big project in rust (3rd for our company, and definitely the most ambitious), and the first thing we're going to do is setup vendoring. We can't afford to play games with crate developers who aren't putting out 1.0 releases of their crates or not following semver properly (I'm going to call out the uuid crate specifically here - sorry, but not really - more are about to be called out).

I don't mind having to maintain forks of stuff to keep moving forward, but there are a LOT of really popular crates that aren't on SemVer 1.0 yet.

Look at the most downloaded crates: https://crates.io/crates?sort=downloads

30 of the top 50 crates downloaded are sub v1.0, and 29 of the top 50 most recently downloaded crates are sub v1.0 - INCLUDING libc. Lib. Fucking. C. futures isn't 1.0, rand isn't 1.0, base64 isn't 1.0, log isn't 1.0, time isn't 1.0 - These all have over 2 MILLION recent downloads, and the authors cannot be bothered to stabilize interfaces. Like, honestly it's pretty unacceptable for the community to be OK with this situation.

For these reasons, we're going to be vendoring almost all of our dependencies. But we're still going to use Rust because we think it's 100% the best option. I just wish that popular crate authors would "bite the bullet" and commit to stable library interfaces for AT MINIMUM one version.

So many of these crates are standard things (uuid, base64, etc) that are based on STANDARDS. And authors are STILL not commiting to stable interfaces. This is honestly mind blowing.

[–]_ChrisSD 4 points5 points  (8 children)

When libc moved from 0.1 to 0.2 it caused big problems for users. I doubt it'll ever go higher than 0.2 unless something happens to mitigate those issues.

[–]kixunil 2 points3 points  (0 children)

Semver trick would help if they decided to stabilize the interface at some point.

[–]nbsdx 8 points9 points  (6 children)

Well, that's what happens when you change interfaces and can't use real semver rules to describe the change. If libc had been 1.0.0 instead of 0.1, then there wouldn't have been breakage (unless people lazily set libc = "*" in Cargo.toml) in a move to 2.0.0. But when you're on semver 0.X, all that goes out the window and you don't get ANY semblance of reasonable dependency management.

Updating dependencies is a NORMAL part of software development, and it will CONTINUE to be a normal part of software development. Keeping things on 0.X versions won't change that, and will only make things harder for users.

Edit: As multiple people have pointed out, Cargo does properly treat 0.1 -> 0.2 as a backwards incompatible change. If this is the case then I don't have any sympathy for people who had issues transitioning to libc 0.2 - that's just part of software maintenance. We all have to deal with it, and if you think you don't you should reevaluate your stance on versioning.

[–]Icarium-Lifestealer 11 points12 points  (0 children)

How would 1.0 to 2.0 have been any easier than 0.1 to 0.2? AFAIK cargo's semver interpretation treats both of these the same (for 0.x versions, x actions like the major version).

I'd guess the problem was caused by either:
1. cargo being unable to link to the same native library from multiple crates
2. using types from the dependency in your public API, which are then incompatible with the same type from a different version of that dependency.

[–]Xiphoseer 10 points11 points  (0 children)

Cargo considers 0.1 -> 0.2 as a breaking change but 1.1 -> 1.2 as a backwards compatible one as per https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements

Publishing a version 0.1 instead of 1.0 is mostly used to indicate that the design of the library or its API surface is not final. That doesn't mean it's not maintained, not dependable or of low quality.

[–]matkladrust-analyzer 7 points8 points  (2 children)

If libc had been 1.0.0 instead of 0.1, then there wouldn't have been breakage

I think you are misunderstanding how Cargo treats semver. For cargo, 1.0.0 vs 2.0.0 is exactly the same as 0.1.0 vs 0.2.0. the relevant docs are here: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#caret-requirements.

[–]nbsdx 1 point2 points  (1 child)

Good point, I updated my comment. But it doesn't change my stance, it only re-enforces it.

[–]dnew 0 points1 point  (0 children)

One might even argue that Cargo does that specifically because of the number of widely-used crates that haven't gotten to 1.0.0 yet, since it's specifically not how semver is defined.

[–]steveklabnik1rust 6 points7 points  (0 children)

If this is the case then I don't have any sympathy for people who had issues transitioning to libc 0.2

The issue is that, unlike a pure Rust library where a 0.1 and a 0.2 can co-exist, there is only one global version of libc allowed. This means it's not just about your code; if any of your dependencies depends on 0.1, you need them to update to 0.2, or you can't update to 0.2 yourself.

[–]TheMiamiWhale 4 points5 points  (7 children)

Why would you not vendor all of your 3rd party dependencies? Just because a crate is 1.0 doesn’t mean it’s public API won’t change. Crate owners can do whatever they want. Whether or not they should is a different matter.

Also, complaining about the authors not stabilizing their APIs is really bothersome. These authors don’t get paid to do this. If you fee so strongly why not spend your free time coming up with a solution rather than criticizing others?

[–]nbsdx 5 points6 points  (6 children)

Why would you not vendor all of your 3rd party dependencies? Just because a crate is 1.0 doesn’t mean it’s public API won’t change. Crate owners can do whatever they want. Whether or not they should is a different matter.

I already use exact versions in Cargo.toml - I don't do libc = "0.2", I do libc = "0.2.69" or whatever. But for a larger project vendoring is better than exact versions, especially if you're using a crate/library that may be less maintained, or that you need to extend with a little more functionality that the author doesn't want. It happens, it's normal. But I would like to think that most crate authors aren't malicious, but rather human and may make semver mistakes. I know I have.

If you fee so strongly why not spend your free time coming up with a solution rather than criticizing others?

I did - vendor your dependencies and manage patch sets or make your own fork. That's the great part about open source.

Maybe I should have worded it better, but this is more of a community problem then a crate author problem (but if more crates authors/groups were inclined to follow standards, it would proliferate throughout the ecosystem). Crate authors would likely be more inclined to follow standard semver rules if the community would push for it more.

I've toyed around with the idea of trying to organize a push for the top 100 crates on crates.io to hit semver 1.0, but frankly it's not worth my time. I have no issue vendoring or forking and maintaining my own versions of things so I wouldn't be a good person to lead that endeavor due to my own stance on open source.

Also, complaining about the authors not stabilizing their APIs is really bothersome.

I don't really feel bad about this, but at the same time I understand where you're coming from. If someone just tosses some code up on github and crates.io, I don't really expect much out of it. But if a group is actively maintaining something that's being used enough that it gets a million downloads a month, I feel that they have a certain obligation to make sure they're following standards that their users expect. But if they don't want to deal with that, that's fine. But at that point the community needs to band together to find a way to maintain it in a way that DOES adhere to standards, otherwise it will eventually be replaced by a competing crate (even if it's less feature complete) that DOES adhere to community standards.

[–]steveklabnik1rust 6 points7 points  (5 children)

I already use exact versions in Cargo.toml - I don't do libc = "0.2", I do libc = "0.2.69"

Note that this is still a ^ version; you would want libc = "=0.2.69" for an exact one.

[–]nbsdx 4 points5 points  (4 children)

Seriously? That's misleading as hell. Thank you for letting me know. I'll be updating all my projects.

[–]steveklabnik1rust 2 points3 points  (3 children)

Sort of; it depends. It's the default, and `^` is what you should want as a default. It is one of the things that various semver implementations diverge over.

[–]nbsdx 2 points3 points  (2 children)

I've been burnt a couple times in node projects because of ^, so I'm likely quite biased here. ^ is great if libraries are REALLY good with publishing APIs that are semver compliant, but 99 times out of 100, I (personally) don't want that because on the off chance someone makes a mistake, your builds break.

That risk just isn't worth it for me, and it makes it really difficult to have reproducible builds. Yeah, Cargo.lock helps, but I shouldn't have to rely on a 2000 line long auto-generated lockfile for ensuring that I have reproducible builds. I get that this is a hard problem - I've written more dependency checking code that I ever had any desire to - but reproducible builds (to me) are more important than anything else.

[–]crabbytag 1 point2 points  (0 children)

You have pointed out an issue - popular crates aren't at 1.0 and haven't committed to a stable API.

You have then pointed out a solution - vendoring. But is vendoring the solution to your problem? Couldn't you just pin a version in your Cargo.toml? Let's say you add rand = "0.7.3" in your dependencies. How does it matter if a 0.8 version is released with a changed API? Your build continues to depend on 0.7.3, as if nothing had changed.

This holds for all your dependencies - as long a specific version is in your Cargo.lock, future releases of a dependency don't change anything for you.

And for what it's worth, the crates you mentioned are good. rand is 0.7 but it's absolutely fantastic. There's a lot of underlying complexity that's been abstracted away well - exposing an elegant API while supporting every platform under the sun (AFAIK).

Edit: I read elsewhere that you want to vendor because you'll make changes to your dependencies. But then you'd be vendoring regardless of whether the crate is at 1.0 or not.

Overall, I just don't see it. I don't see rand and others not being at 1.0 as a sign of instability or immaturity, nor do I see vendoring as the solution to that perceived immaturity.

[–]theZcuber 0 points1 point  (0 children)

Maintainer of time here. It was stuck at 0.1 for years, and only had development picked up late last year. Pick-up of 0.2 has been relatively slow, what makes you think a 1.0 would be any different?

There is a road to 1.0, I just want to see additional features land in the compiler before that happens. It has nothing to do with me "not being bothered" to commit to stable interfaces. Merely saying that is rude at best. Interfaces are stable within each pre-1.0 minor version, that's what semver is in Rust.

[–]othermike 20 points21 points  (11 children)

most libs follow semver guarantees to not be a concern for the user

You mean most 0.x libs? What semver guarantees would those be? The semver homepage itself explicitly says

Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.

[–]dpc_22 7 points8 points  (5 children)

Yes I am aware. But most maintainers treat 0.x as major releases and 0.0.y as minor and backwards compatible. So it's a later on top of semver

[–]tinco 12 points13 points  (4 children)

The whole reason for staying on 0.x is that you expect your current api has some significant deficiency that you may or may not have discovered. It means at some point there's going to be a 1.0 that has a different api.

[–]__i_forgot_my_name__ 9 points10 points  (1 child)

Breaking changes may still happen after 1.0 by doing a 2.0 release, and you can climb to 3.0 and then 4.0 and then 5.0 as fast as you got from 0.1 to 1.0 because it's not like you're going to run out of numbers. I've seen libraries sitting at 10.0 in the Rust ecosystem, and meanwhile Rand is sitting at 0.7 and yet it's probably older and broke less then most libraries.

[–]myrrlyn 4 points5 points  (0 children)

rand is probably the worst example you could've chosen for this, as it's been extremely unstable. libc, however, is essentially frozen at 0.2 despite being a stable binding to the platform C library with no ongoing development or API changes.

[–]Floppie7th 1 point2 points  (0 children)

Or it means that you don't know what you don't know. You aren't necessarily confident that it will change; you might just not be confident that it won't change.

And, either way, library users can just keep a version pinned if they don't want to refactor to handle major API changes, making it mostly a non issue.

Even with semantics, version is still just a number.

[–]kixunil 0 points1 point  (0 children)

It means at some point there's going to be a 1.0 that has a different api.

Not really, I think. A crate author could be uncertain about the API and at some point later confident to mark the same thing as 1.0.

[–]EarthyFeet 2 points3 points  (4 children)

That's not the convention that's used on crates.io, FWIW.

[–]othermike 5 points6 points  (3 children)

That's fine, but in that case I think it's potentially confusing to refer to "semver guarantees". The main point of semver was to establish a consensus on what version numbers mean; if you're doing something else, you should probably call it something else.

[–]_ChrisSD 7 points8 points  (2 children)

Cargo uses a variant of semver. Unfortunately I don't think it has name but it says that only changes to the first non-zero number is considered breaking. For example 0.0.1 to 0.0.2 is breaking and so is 0.1.1 to 0.2.0. But 0.1.1 to 0.1.2 isn't.

[–]steveklabnik1rust 7 points8 points  (1 child)

Maintainer of both semver (the spec) and semver (the rust library cargo uses) here.

The real issue is this: the semver spec does not define what ranges are. Every major implementation of semver defines ranges to do this.

I am hoping to eventually move ranges into the semver spec, which will clarify all of this. It's not super high on my priority list though.

[–]_ChrisSD 1 point2 points  (0 children)

I think having some clarity for users would be really useful. I'm glad its on your radar!

[–]tspiteri 1 point2 points  (3 children)

The problem I see in remaining below 1.0 when the API is stable is that you cannot distinguish between patch releases and minor releases using semver. So when I see a dependency has an update from 0.3.4 to 0.3.5 I don't know if it's only bug fixes which I want, or new features that might change some behavior. Even if the change is in something undocumented and subject to change, I don't think it should be changed in a patch release.

[–]Icarium-Lifestealer -1 points0 points  (2 children)

Cargo-Semver interprets 0.x versions as 0.major.minor.patch, so you should expect 0.3.4 to 0.3.5 and 3.4 to 3.5 to contain the same kinds of changes.

(of course that assumes the crate follows cargo-semver, which isn't guaranteed, especially for 0.x versions)

[–]tspiteri 1 point2 points  (1 child)

And that is my issue. If there is an only-bug-fixes release before 1.0, you would still need to make a minor release, so it could be a minor release cargo-semver-wise, but in fact be a patch for a bug. I don't think four parts as in 0.major.minor.patch are a thing, you would just have 0.major.minor.

[–]Icarium-Lifestealer -1 points0 points  (0 children)

Is there any issue on the tracker about supporting 4 part versions (at least for 0.x)? I would have expected cargo to support that, but apparently it only supports 3 parts.

[–]davidw_- 0 points1 point  (0 children)

worst than that, the standard library is pretty empty...

[–]wsppan 0 points1 point  (0 children)

Thanks for that link at the end. Kinda like the Cliff Notes of Rust!

[–]radicalzephyr 26 points27 points  (3 children)

The us the most thoughtful and informed critique of Rust that I know of directly, though it’s written from a slightly different perspective.


Other than that you might try reading the blogs that people have written at the end of the last few years for the year-end round-up https://blog.rust-lang.org/2019/10/29/A-call-for-blogs-2020.html (search for #rust2020)

The purpose of these has generally ben to find the pain points for veterans and newcomers and generally discuss how to keep improving Rust as a community and a language.

[–]shinazueli 5 points6 points  (2 children)

Honestly, I just find the single biggest "pain point" is exactly as described in that link: when people want to directly port imperative mutable code to Rust, they're just going to have a bad time because Rust is almost specifically designed to force you to design it correctly with respect to mutability.

So they whine that "Rust is hard."

No, it isn't. It just won't compile your bullshit. It has dead simple rules, and it enforces them. One working day of reading the "book" and working through the examples should be enough to familiarize any working engineer with the language, especially if you're already familiar with C or C++.

(If you aren't familiar with it, then it's kind of unfair to compare Rust to anything but C-like learning curves, you just get more compiler errors and less runtime crashes while you're learning.)

The "hard part" of Rust is taking that knowledge and applying it to existing designs that don't actually work properly. "but if I could just..." No. That's the point. You can't "just".

[–]Icarium-Lifestealer 12 points13 points  (1 child)

It has dead simple rules

Rust has pretty complex rules. e.g. the memory model (stacked-borrows, pointer providence, etc) or trait coherence.

One working day of reading the "book" and working through the examples should be enough to familiarize any working engineer with the language, especially if you're already familiar with C or C++.

Superficially perhaps, which should be enough to write ordinary business code. But once you get into the advanced parts the complexity of Rust matches that of C++.

Between the complexity and the lack of a single up-to-date specification I often spend hours digging through random bugtracker issues and RFCs (which might have been superseded or not implemented yet) to figure out what's allowed or possible.

[–]shinazueli 1 point2 points  (0 children)

lots of fancy terms

It's really, really simple if you follow the books and documents. If you insist on trying to make everything as complicated as possible, then yeah, sure, but in a relative comparison it's really not that hard. "You generally can't have more than one mutable reference to the same object" covers most of the rules in a single sentence. (And yeah, if you want to language lawyer it, I'm sure you could point 95 billion holes in it, but the reality is that for ordinary use that's all you need to know.)

ordinary business code

I mean, that's generally where I'd draw the line for a discussion about "learning curves".

For advance stuff then I'll say that there's nooks and crannies in every language, even fucking JavaScript has some nasty shit if you go looking for it.

[–]Ixrec 23 points24 points  (2 children)

Because Rust is such a new language, nearly all "well-written criticisms" are either:

  • describing the fundamental tradeoffs that Rust makes (e.g. it has a higher learning curve than Go/Python/etc, because how else would it give you more control over runtime behavior?), or
  • pointing out that it's less mature/established than other languages, or
  • essentially wishlists of features/libraries that don't exist on stable yet

That's probably why most people blogging about Rust this way just cut out the middleman and call what they're writing a feature wishlist. While there are things in the language that the community largely agrees in retrospect were a mistake, they're mostly very small things (like a missing trait impl in std) which wouldn't make much sense as responses to this post. It'll probably take years before anything big lands on that list.

Of course, that's also a bit of a cop-out. Unfortunately it's hard to give more concrete criticisms or advice without zeroing in on a specific language or application domain, since Rust itself is used in so many ways none of the possible criticisms really apply universally either. But a lot of it is also pretty obvious, e.g. if Go is the language you're most familiar with, then obviously you're likely to have some trouble adjusting to Rust not having a GC and requiring you to understand which types own what memory and which are "just" references. And if you do a lot of async network I/O, then obviously Rust's async ecosystem is still in a lot of flux so that may not be what you want just yet.

Still, there's also quite a few non-obvious things I can point out that might be of some use, and are not likely to be completely invalidated within a year or two of me writing this:

  • Rust has no complete formal specification. In practice it's debatable to what extent C and C++ really "have a spec", considering no one can seem to agree on what their specs mean, but there are application domains that expect a formal spec and therefore accept C, C++, Ada, etc but will not accept Rust yet.
  • People used to C/C++ or GC'd languages often find it surprising that self-referential types, including data structures with reference cycles, are much more difficult to write in Rust. Especially because they never thought of themselves as writing "self-referential types" until asking someone here about a Rust compiler error.
  • In terms of "high-level" type system features, Rust is conspicuously missing const generics (for making arrays of any size "just work"), specialization, and GATs (roughly equivalent in power to HKTs). Anyone familiar with C++ templates, or constexpr, or pure functional languages like Haskell will know whether this matters to them.
  • In terms of "low-level" features for performance or bare metal, Rust is conspicuously missing inline assembly, "placement" allocation, some parts of the uninitialized memory story, safe type punning / transmuting (there are crates for this, but the soundness is often unclear), and const generics (for efficient and ergonomic numerics libraries). Again, you probably know if these matter to you.

I'm sure everyone here has different lists they could throw out, but hopefully that's better than nothing.

[–]bboozzoo 1 point2 points  (1 child)

In practice it's debatable to what extent C and C++ really "have a spec", considering no one can seem to agree on what their specs mean, but there are application domains that expect a formal spec and therefore accept C, C++, Ada, etc but will not accept Rust yet.

That's because C, C++ and Ada are all covered by respective ISO standards. Development of each is driven by actual committee with multiple stakeholders and multiple implementations. I don't know about Ada, but unfortunately C and C++ have plenty of Implementation Defined Behavior what causes people believe there is no formal spec because implementations tend to behave differently (also why it's called implementation defined n the first place).

[–]mo_al_ 0 points1 point  (0 children)

Compiler extensions in C/C++ are a good thing, even if they veer off the formal spec. They drive things like proposals and other imporvements to the language.

[–]parabol443 57 points58 points  (19 children)

  • Compile time / link time is still a problem - slow for prototyping

  • Missing libraries / immature / untested ecosystem: many of the hard problems that you'd use Rust for like video / audio decoders, desktop GUI, game engines, webdev (i.e. something with the ease of use of Spring), datascience libraries (i.e something like matplotlib or similar python frameworks) are unsolved / missing

  • IDE support is still garbage overall (JetBrains is currently the frontrunner), racer doesn't have incremental parsing, so very slow autocomplete - improvements are coming, but again, the current state is still bad

  • Usually devs put more focus on performance than usability: ex. so far there isn't a single web framework / libraries with which you can write a simple web forum (login / user registration / etc.) in less than two weeks, no crate that can handle auth properly, no easy bindings for paypal / stripe integration (read: no money) or anything to write a "proper" website with. Java / C#, Python, Ruby all run circles around Rust in the webdev department

  • LLVM doesn't always produce the absolute fastest assembly, GCC usually does

  • often hundreds of dependencies due to the minimalistic crate design, may turn people off

  • some people ignore semver, leading to build problems - rare, but it happens, cargo has a very "silicon-valley style" of handling dependencies - aka upgrade fast and break things

  • lol no jobs (yet?)

  • very specialized usecase: "system tools" are usually not the big money-maker, webdev / mobile is, Rust doesn't have a "focus" like other languages, jack-of-all-trades, master at none language

  • Rust doesn't have as much marketing as Go - just saying this because even if a language is shit, what matters is how big the company behind it is: Oracle - Java, Google - Go, Microsoft - C#. Mozilla isn't nearly as big as the other ones, even if they think they are

In the end, programmers would like programming to be about merit where the best technology wins, but programming is a business. Managers have to make tradeoffs, "how big is the hiring pool", "will this language be supported in 10 years", "is framework x officially supported", "are there enough libraries to support our use case", "is the extra performance worth the cost", etc.

It's definitely great for hobby programming, whether it's professionally adopted is another question.

[–]smmalis37 33 points34 points  (0 children)

You should check out rust-analyzer if you're still using racer, it's miles better.

[–]Devildude4427 8 points9 points  (0 children)

• ⁠Usually devs put more focus on performance than usability: ex. so far there isn't a single web framework / libraries with which you can write a simple web forum (login / user registration / etc.) in less than two weeks

I don’t know the exact scope in your mind, but I’d certainly have no problem busting out a simple web forum with Rocket in two weeks.

no crate that can handle auth properly

Depends on what you’re looking for.

no easy bindings for paypal / stripe integration (read: no money) or anything to write a "proper" website with.

I’d argue that you should be using a dedicated front end, not Rust, for that. Use the correct tool for the job.

[–]normtown 2 points3 points  (2 children)

often hundreds of dependencies due to the minimalistic crate design, may turn people off

This is not unique to Rust. Ask anyone that’s used NPM or Bower or Ruby gems. I agree this is a problem, but it seems to be a much larger recent phenomenon (possibly stemming from 2.0 web dev).

[–]julian0024 1 point2 points  (1 child)

My "small" boilerplate react starter kit has some 250mb of dependencies in npm. It compiles down to less than 350kb for first page, but I would argue it's much worse than rust.

[–]UnpossibleJim 2 points3 points  (1 child)

I actually do agree with all you said, but Microsoft is working on Project Verona (I think I spelled that correctly) which is a Rust style language to replace C and C++ in their systems programming to patch up security issues. I can only assume that it's Rust with some of the issues you mentioned touched on (if I had to guess, and I am, a switch to GCC, integration into VS - though that's a separate matter - some specific libraries). This type of language is going to be adopted, even if it isn't Rust. Rust may just end up the C to Microsoft's C++ as it were. (Full disclosure, I am a Rust fan, so I'm not unbiased. Take what I say for what it is)

[–]pjmlp 0 points1 point  (0 children)

Do you know how many programming languages Microsoft Research has looked throughout the years?

Haskell, Axum, OCaml, System C# (aka M#), Sing#, Phoenix Compiler toolchain, Dafny, TAL, F*, Checked C, Z3

These are just a couple that I remember without going through my papers collection.

That is what MSR Programming languages and software engineering department does, language research, it doesn't mean they get to come into Microsoft products.

[–]Floppie7th 1 point2 points  (2 children)

there isn't a single web framework / libraries with which you can write a simple web forum (login / user registration / etc.) in less than two weeks

That's a funny way to spell "hours"

[–]shinazueli 7 points8 points  (1 child)

Not sure why you're downvoted. Maybe 4 hours of work. Maybe.

[–]Floppie7th 9 points10 points  (0 children)

To implement a simple web form and an endpoint that does something? Yeah, even the less ergonomic frameworks like actix-web (which is what I usually use, more out of habit than anything at this point) can have you up and running in a time measured in hours, not days or weeks. Rocket and Warp are both even easier.

Not that I can write this minimal example more quickly in Rust than in Go, but the difference is pretty minimal. What you want to do with that endpoint might be much, much easier in one language over another, though. Primarily dependent upon the available ecosystem.

[–]lampishthing 0 points1 point  (6 children)

Isn't Facebook's coin offerring in Rust? Libra?

[–]Treyzania 2 points3 points  (3 children)

Libra is (more or less) a dead project at this point. And thank god for that.

[–]lampishthing 1 point2 points  (2 children)

I'm not so sure, I think they're going to keep plugging away at it for at least a while longer. It's not in the news anymore... it'll be a lot easier for them to get regulatory approval without media focus, and the regulatory hurdles were what seemed to scare all the partner organisations off the project. That said, I'd imagine they'll struggle and any success is by no means guaranteed.

[–]Treyzania 1 point2 points  (1 child)

Multiple countries (France, Germany of the top of my head, though there's others) have said "no this will never be allowed within our borders ever". And in the US with how angry incumbents have been getting at the "big 4" tech corps lately I doubt regulators are going to play ball with Facebook any time soon. Plus a few of their key partners have already pulled out of the deal so it's unlikely they'd have the reach to push for any real adoption even if they do get approval.

[–]lampishthing 1 point2 points  (0 children)

Yeah I do know all this but the pessimist in me says facebook has the warchest and the time to make this happen. Political focus and politicians come and go. Facebook are trying to commoditize something that's of almost limitless value, that nobody currently has solid control over, and that is esoteric enough that the general population won't care about. It's the kind of fight that the moral ground doesn't typically win.

[–]_ChrisSD 26 points27 points  (13 children)

It should be noted that Go and Swift are usually the wrong comparisons to make. Rust is lower level with manual memory management. This is very different to a garbage collected language. There can of course be overlap in usage but Rust is much more comparable to C++ than anything else.

[–]Hairy_The_Spider 14 points15 points  (2 children)

I'm new to rust. But I actually found it VERY similar to Swift. Of course, they aren't used in the same domains, but I found the feel of the languages to be pretty similar.

Here's a non-exhaustive list:

  • Focus on "strong" typing. No null, option and result types which must be explicitly checked or transformed.
  • Both languages have a functional "feel" to them.
    • Liberal use of higher-order functions.
    • Enums which carry around extra values (sum types).
    • Accompanying the above, great pattern matching
    • Eager by default data structures, but having the option for lazy evaluation.
  • Both languages have a "value objects first" mentality.
  • Extensions for data structures.
  • Trait inheritance.
  • Traits with associated types.
  • Generics that "inherit" (I forgot what this is called, like <T: Foo>).
  • Conditional conformance in extensions.

This is of the top of my head. I believe there are more which I don't remember right now. As I said, I'm new to rust, so I might be wrong in some (or several) of these. But I found that picking up Rust a breeze because of Swift (except for life-times, which are a totally new concept to me!).

[–]PM_ME_UR_OBSIDIAN 7 points8 points  (0 children)

This is just the direction of the industry right now. Kotlin is in the same boat.

[–]loamfarer 1 point2 points  (0 children)

Generics that "inherit" (I forgot what this is called, like <T: Foo>).

Inherit isn't the right way to frame that, at least with rust. It would be better to call that feature generic type bounds/constraints, in a language agnostic sense. In Rust's case the bound is a trait bound.

[–]AVX-512 8 points9 points  (1 child)

People can make any comparisons they want. Comparing things that are different is the point of comparing things. If things were the same a comparison would then be useless. Don't think about comparisons as a sport where it needs to be fair. Comparisons are for deciding what is the right tool to use for a particular person on a particular task. There are many people and tasks where one might want to use Go, or Rust.

[–]_ChrisSD 4 points5 points  (0 children)

Sure. But the title is "criticisms of Rust" and the only other mentioned languages are garbage collected. So it's worth pointing out that they exist in different spaces (although, as I said, there is overlap).

In general it makes sense to go with the garbage collected language if there's no reason not to use garbage collection. It solves a lot of memory issues for the programmer.

[–]pjmlp 1 point2 points  (1 child)

Swift is the future of systems programming on Apple platforms, so the comparison makes naturally sense.

Swift is intended as a replacement for C-based languages (C, C++, and Objective-C).

-- https://docs.swift.org/swift-book/index.html

Swift is a successor to both the C and Objective-C languages.


By the way, I wouldn't be surprised that when Kotlin/Native finally reaches 1.0 that Google wouldn't promote it C++'s companion on the NDK.

[–]_ChrisSD 0 points1 point  (0 children)

Fair enough. I admit I'm not too familiar with Swift.

[–]OS6aDohpegavod4 2 points3 points  (1 child)

I disagree. Rust isn't just for systems programming; it's a general purpose language which is also viable for systems programming. Rust is great for things like normal web servers, for example, and devs who are building a web server are going to be comparing it with Go or Node or whatever else they want.

[–]r0ck0 1 point2 points  (0 children)

things like normal web servers

Just to clarify... by this do you mean writing APIs and website backends? Or writing alternatives to nginx/apache?

[–]_Js_Kc_ -5 points-4 points  (3 children)

C is manual memory management. What about Rust or C++ is manual memory management (other than it being an option if you really need it)?

[–]_ChrisSD 12 points13 points  (2 children)

In both C and C++ you decide when to allocate and free memory. In C it's often done with wrapper functions, usually called "malloc" and "free". In C++ it's done with RAII classes.

But if you want to be really pedantic, then neither is doing manual memory management. That's usually handled by the OS and the C library. However, this is not what I meant in my first comment.

[–]_Js_Kc_ -4 points-3 points  (1 child)

In C, I have to call free (or some additional wrapper around it) manually every time I'm done using a piece of memory.

I don't have to do anything when an Rc or a shared_ptr (or a stack-allocated object) goes out of scope. The deallocation, from a high-level point of view, is automatic. As automatic as in a garbage-collected language.

That's a meaningful distinction. Pedantry is what you're doing.

[–]_ChrisSD 4 points5 points  (0 children)

If you honestly can't understand what I meant by comparing "manual" with "garbage collected" memory management then I don't know what else to say.

[–]angelicosphosphoros 21 points22 points  (1 child)

  1. When I learned Rust, I started to dislike writing code in C++ but I have to on work.
  2. Some data structures like trees/linked lists are hard to implement without unsafe. But unsafe implementation doesn't much differ from C++.
  3. It is a specific disadvantage for me but I miss the really good game engine like Unreal Engine 4.

[–]meamZ_MZ 5 points6 points  (0 children)

Some data structures like trees/linked lists are hard to implement without unsafe. But unsafe implementation doesn't much differ from C++.

Yeah i mean... that's kind of what's great about rust. You have the choice of implementing it safe. In C++ you don't really have that choice.

[–]brokenAmmonite 8 points9 points  (1 child)

A slightly weird critique I don't see often: Rust's name resolution is extremely complex and underspecified. There's a bunch of different systems that interact in subtle ways -- "standard" name lookup, trait resolution, macro_rules!/imperative/built-in macro expansion, old-style macro resolution, new-style macro resolution, rust 2015 vs rust 2018, cfg attributes, filesystem lookups, cargo version resolution, ...

And you can't just not implement any one of these! They all affect each other, so if any one is left out lots of names won't resolve. Also, they don't run one at a time; for example, you need to expand macros to look up names, but you need to lookup names to find the source for the macros. This makes implementing tooling like IDEs really hard. (People often point out that rust has poor IDE support, and I think this is basically why that is.)

I suspect this is also a major landmine for efforts trying to get Rust approved for use in safety-critical systems. It's gonna be hard to formally specify something this complex.

This is mostly because of rust's focus on being a compile-time language; there's no separate preprocessor like in c/c++, but you still need features like that, and there's no reflection, so everything gets baked into the language, with bits and pieces growing and interacting organically over time. The next backwards compatibility break might be a chance to clean some of this up.

[–]loamfarer 0 points1 point  (0 children)

Granted, I've found it far better than most languages that have come before it. Specifically those with comparably rich feature sets. Generally I find most cases to be intuitive once learned. It doesn't present as yet more learning curve, but the benefits of Rusts modules and name-spacing really facilitates clean design, and helps to get refactors correct.

[–]kredditacc96 12 points13 points  (1 child)

Unrelated to your question, but the link you provided has some pretty shallow criticisms, which is quite "jerkable":

https://dzone.com/articles/i-don%E2%80%99t-much-get-go (Jon Davis, 2010) * no language interoperability (only C) * no versioning model * no OOP * has pointers * no semicolons at line endings * no this * no function/operator overloading * no exceptions

[–]cbmuser 9 points10 points  (0 children)

  • No alternative implementation (yet)
  • Limited portability due the limited number of targets supported by LLVM

Both is being worked on in various projects (mrustc, gcc-rs, new targets for LLVM) and I’m contributing myself to these efforts.

[–]AVX-512 8 points9 points  (4 children)

Some personal criticisms:

Compile times are much slower than Go, or C, and many other languages.

Rust is a very big language that is very hard to wrap your head around, very hard to understand other people's code, since they may be using complex features that you haven't, or in ways you haven't. Rust is similar to C++ in this way.

The borrow checker rejects correct programs. You have to then work around the borrow checker, or use unsafe. This adds cognitive load compared to garbage collected languages, and can sometimes be a performance hindrance compared to C or C++, if you are unwilling to use unsafe. Also sometimes satisfying the borrow checker requires peppering your code with lifetime annotations which gets really complex and ugly.

It is not necessary to reply to me with the usual replies to these criticisms, I am aware of all of them, I like Rust, these are just downsides that exist. Everything has downsides.

[–]Suitable-Main -2 points-1 points  (3 children)

Rust is a very big language

Would you really describe Rust as "big"? I agree that it's very rich and hard to wrap your head around. But small things can be hard to understand as well. Scheme is a very small language, but macros and continuations are both tricky things to get your head around. A subset of Haskell could be very small but really getting lazy evaluation and its implications is hard.

The criticism itself (that it's hard to understand and hard to read other people's code because they might use advanced features) completely stands, but I'm curious to hear your take on this point.

[–]AVX-512 4 points5 points  (2 children)

Haskell seems pretty big too, but I'm only vaguely familiar with it. Examples of "small" languages would be Go, and C, and maybe early C# and early Java.

Languages do tend to expand over time, and that has downsides.

[–]_ChrisSD 5 points6 points  (0 children)

C's size is deceptive. It overloads a lot of symbols and keywords for use in different contexts (as do most languages). Scheme is far far smaller by comparison. Its specification is tiny (for a programming language).

[–]PM_ME_UR_OBSIDIAN 2 points3 points  (0 children)

Haskell is huge, especially if you take into account all the widely used language extensions.

[–]lucasholderx 4 points5 points  (4 children)

I started Rust about a month ago. I would say my biggest criticism would be the availability of libraries and compilation times. Two examples regarding libraries:

1) I was a bit disappointed to find out that a lot of the async libraries are tied to a particular runtime. For example, I wrote an API client library using the reqwest crate and then started building a web backend with tide. I then found out I wouldn't be able to use my API client because reqwest is tied to the tokio runtime, whereas tide is tied to the async-std runtime. For now, I've decided to not use async at all until there is a clear winner in terms of runtime or until runtime agnostic libraries become the norm.

2) I needed [cursor based pagination]() for my web backend but diesel, the ORM I'm using, doesn't have such function out of the box and I couldn't find any crate that does this. It turns out that extending diesel to provide such functionality is quite difficult for a noob and I'm still not sure whether I'll manage to do it.

That said, I still very much enjoy Rust and am glad I picked it up.

[–]sasik520 4 points5 points  (3 children)

1) I was a bit disappointed to find out that a lot of the async libraries are tied to a particular runtime

Although I don't use async much (yet?), this is something that I totally don't understand and I think it kills the idea of multiple runtimes.

[–]steveklabnik1rust 2 points3 points  (2 children)

this is something that I totally don't understand

The short of it is: it's being worked on, but it's not done yet. The largest blocker to interop, Futures, was standardized. But there are still other interfaces that will be needed, and it's not clear what those should be yet. We'll get there.

[–]Xychologist 0 points1 point  (1 child)

This is definitely at this point my largest "real" complaint with Rust. Async-std is great, it's an achievement, it may be better for many use cases than Tokio... but I really wish it hadn't been created. At least not until the necessary abstractions had been developed and it could have avoided splitting the ecosystem. As it happened we had a bifurcation almost immediately upon async/await release and essentially everyone's introduction to the feature has been coloured by that conflict. Some crates dealt with it well (e.g. sqlx with a feature for each option), others not so much. It's not Rust's fault, but it was a major error in coordination.

As complaints go, it's objectively pretty minor, but it is bitter.

[–]LovelyKarlureq 0 points1 point  (0 children)

I think the direct opposite. Great that we got a serious second runtime this quickly, because the eco-system around tokio was becoming a monoculture. Now a lot of people are seeing and thinking about the issues around socket/file and runtime. Ultimately that speeds up the innovation needed to abstract this. And that means the day we can have proper delineation between library and runtime is much closer. Yay for async-std! Yay for tokio!

[–]yesyoufoundme 1 point2 points  (0 children)

As a non-expert, here is my take on nitpicks of Rust (though, I love Rust!).

  1. Incomplete features. Things like impl Trait are so awesome when you can use them, it really makes you wish it existed in more places.
  2. Features in progress. Things like GATs. You'll often find some RFC being worked on and realize how much your life would be different with that was finished. Not Rust's fault mind you, some things are just still a WIP.
  3. The Async / Sync divide. At work it's been a bit hairy having to make choices on what libraries to use, since not everything uses Async yet. Rocket is a big one for us.

With that said, I still love Rust. Use it daily, use it at work, etc. It's a joy for me.

[–]godojo 2 points3 points  (0 children)

Most of the criticisms I see are almost completely dependent on what it is being compared to.

The tools and the libraries are always being worked on. So a factor for those is really the community size and the funding, which for Rust is on a ramp up but clearly is not seeing any explosive growth.

The language itself, the grammar, is a function of the constraints given or chosen; Rust and it’s developers do self-impose a lot of constraints and often generate polarizing discussions.

It’s hard to build constructive criticism in one place on a thing this large and with so many thought leaders. I do like the call for blogs approach, this does generate debates in varying and specific subject matters. It’s probably important to point out that Rust is not driven by one person but through a complex set of communities of interests.

[–]maxfrai 2 points3 points  (0 children)

The main problem for me is async trash state.

Splitted ecosystem and no exact view how to make things better for now.

[–]Rhodysurf 1 point2 points  (0 children)

The worst part for me is dealing traits and having to manually find which traits you need to import to use the functionality even if it is already implemented in the same place as a module you have imported.

I understand why, but in practice it sucks. Ideally the IDEcould autocomplete and auto import the traits available, but it doesn’t unless the trait has been imported. It makes the mental load way too high.

[–]shinazueli 1 point2 points  (0 children)

Most of the "criticisms" of Rust are based on where you are coming from when you learn Rust.

It has a simple bifurcation: you either are coming from C++ or you are coming from Python/Java/Js/Go.

If you are coming from C++, nearly all of your complaints will be about the borrow checker and mutability and crate stability and the need to use crates at all. Crotchety old programmers fit here. "just let me use std for everything and be unsafe and basically make this C++ in another language!!"

On the other side, if you're coming from a world where you didn't understand what a type was, or from a world where you had to learn what a heap or a stack was, or where you could hit the F5 key and see your code run instantly, then those things are going to be what you complain about: "long" compile times, "why doesn't it have a GC", "why does it have to be so verbose and make me write types", etc. Younger, "web dev" "I can copy from stack overflow" programmers typically fit here.

Basically, whining about "make this language more like what I already know".

Edit: there's also a smaller group of "pure functional nerds" that complain in an entirely different direction: "why can't this just have every feature of Haskell in the first year of its existence?" If at any point one complains about the absence of a monad, they belong in this small group.

[–]DreadY2K 1 point2 points  (0 children)

There have been a lot of people already posting things, but there was one thing that I noticed when I learned rust that doesn't seem to be mentioned in any of the other posts here:

It has "infected" my approach to C and C++. By this, I mean that I try to personally apply the ownership ideas to my code in those languages. I don't know if this is a good thing or a bad thing, but it's something that I've noticed since I started learning with it.

[–]jkoudys 0 points1 point  (0 children)

Rust can give you so many ways to do something, it's easy (especially early on) to get decision paralysis trying to decide on the "right way" to do it. Take getting a String - you could String::from, .to_string(), .to_owned(), .into(), format!, and probably a bunch more I've missed.

Go will limit you, and while you may not like the options you have, it's pretty obvious what approach to take. Go is definitely easier to start with, and especially for distributed teams working newer projects, much simpler to collaborate because you all understand each other's code.

[–]Lighty0410 0 points1 point  (1 child)

Uhm, i really-really-really love Rust. And i love writing pet-projects using Rust.

But (sadly :( ) i have to use C++/Go on my job.

I cannot say exactly about its cons, but there are my thoughts after ~3 month of using it.

Rust has relatively steep learning curve. But what i find interesting: after you have to overcome it, Rust becomes one of the most readable language (at least in my experience).

As a subcase: Rust's syntax is kinda esoteric.

Another thing is (maybe it's me, idk) that writing in Rust means you'll always have to learn something new: for example, i didn't know about let &t = &T pattern-matching even though i finished writing couple of pretty decent pet-projects. And there are a lot of thing like this and i really like it! But it might be a huge stopping factor for someone else.

[–]MrK_HS 1 point2 points  (0 children)

after you have to overcome it, Rust becomes one of the most readable language (at least in my experience).

I don't know how to describe the reasons for that, but that's exactly how I feel about it. Most I can say, that maybe is close to the ground truth, is that the syntax is well structured and without ambiguities.

[–]jsomedon 0 points1 point  (0 children)

not exactly about criticisms but something similar: not yet awesome rust

[–]orion_tvv 0 points1 point  (0 children)

I wish Rust had:

  • more extensive stdlib. It would decrease fragmentation of creates. In python we see few library for some stuff and dozens times more in js because of it. It also makes harder to maintain tons of dependencies even for small project. It's better to have good few common crates instead of reinventing wheels.
  • explicit set of philosophical rules like python's zen.
  • force single format style all code for all creates. It's the only advantage of go against rust.

[–]snnsnn 0 points1 point  (0 children)

List is very misleading for someone who doesn't know Rust becase there are lots of outdated stuff. Some of them doesn't even make sense.

[–]kixunil 0 points1 point  (0 children)

I ranted a few times, but never in writing. Some things that annoy me: * io::Error impractical for my purposes (see also my recent post) * Lack of GAT (thanks a lot to all people who work on it!!!) * Debug in the impl of Termination trait * Lack of delegation * No way to generate a snippet for arbitrary trait impl in Vim. * Lack of refactoring tools for Vim * Forces me to think about in-memory representation even in projects where it's not that important. * Bunch of nitpicks that I don't care to write down individually.

[–]firefrommoonlight 0 points1 point  (0 children)

These are tangential, but a language can't effectively be separated from its ecosystem and community.

  • Many published crates provide little documentation or examples, or have stumbling blocks that are easy to run into, and could be addressed by the authors trying the crate with fresh eyes, or writing instructions.
  • The status of GUI libraries is poor.
  • While making web backends in Rust is popular, the tooling isn't as robust as what's available for Python/Django, Ruby/Rails etc. Eg there's no high-level ORM, no batteries-included (or avail) web frameworks with admin, email, auto migrations, authentication etc. I see many posts here about actix, warp, diesel, rocket etc, but relatively speaking, these are micro frameworks that are missing features you need for most websites. Unlike Python microframeworks like Flask, you can't just bolt on the features, because they don't exist.
  • I prefer indentation over braces, and lack of semicolons. I find myself in unclosed brace hell often, and we're duplicating information with indents and braces. The semicolon thing would be hard to extricate from the implicit returns, and inner returns denoted by presence / absence of semicolons. Both add noise when reading code.
  • While rust has (arguably) he best dependency and package system of any lang, it still runs into trouble when linking C and Fortran libraries. Do y'all know if there's a way around this that doesn't involve recoding things in Rust? Maybe built in tooling that can download these packages into containers that are work transparently, provide easy access to static linking, or give you better error messages like You're compiling/running this package on a old Linux distro, but dependency XYZ was built for newer distros, and Windows. Consider using feature *XYZ* to use the Rust-only version? Might be out of scope.
  • Traits work via methods, which means calling things as methods that would normally be fields.
  • No built-in constructor for HashMap. I understand there are competing types, but this is treated as a standard feature in most languages, and the insert syntax is verbose / repetitive.

It's notable that my criticisms fall in the areas of immature ecosystem and subjective.

[–]mardabx -2 points-1 points  (0 children)

Username checks out

[–]cthree87 -5 points-4 points  (0 children)

Honestly you could have tried it in the time you took to write this post. Just install rustup and start working though tutorials. Nobody can tell you if YOU will like it.

Jump in.