Hacker News new | past | comments | ask | show | jobs | submit login
Rust Survey 2021 Results (rust-lang.org)
166 points by surfingninja on Feb 16, 2022 | hide | past | favorite | 133 comments



I'm definitely in the camp that worry about the feature/complexity creep. I saw it with Haskell. Haskell 98 is a pretty nice and simple language. GHC Haskell is a monster. This matters when you try to read other people code and the overuse of experimental cool new features becomes a major burden for comprehension.

Rust is already a very large language and for intrinsic reasons pile on a load more complexity than Haskell (just look at the iterators).

I write this as a fan and advocate of Rust.


Rust is necessarily a comparatively large language, but I’m content that at present it’s not getting noticeably worse: additions are mostly filling things that could be expected but are missing, plus some focusing on improving ergonomics.

Take generic associated types, for example: they’re a major new feature… but are conceptually just removing a potentially surprising limitation.

Or const generics: they really are a major new feature, but in general the code that can use them was a good deal more complex and inconsistent before.

You’d have a stronger argument about complexity creep on async—there was lots of demand for it, but it’s not clear that the design that is now frozen was in fact ideal.


One of the annoying things though is lots of the fills are rather inelegant extensions of APIs. They’re not nonsensical, and TBH I don’t really have a solution, but e.g. allocators support (between custom allocators and faillible allocations) ultimately doubles the size of Vec, or near enough. This makes going through the API a major chore.

But maybe this would be better fixed through Rustdoc, by supporting topics / sections, and being able to “globally” set which standard topics you’re interested in e.g. I don’t do embedded so generally unsafe and explicit allocations I’m uninterested in, that stuff could be folded away / hidden in both the sidebar & main text.


I feel like rustdoc has been going through cycles of being useful, then growing beyond what the current design can handle well, and needing major changes again. It’s currently not good for discovery in std, because each type has far too many methods and each method has far too much text, with examples added to everything.


That's not wrong.

Wrt examples I feel like the examples are mostly obvious / uninteresting and thus have little value, but I’ve been in the field a while so that may well be an experience bias.

Alternatively some examples show the neat bits but not clearly because they’re artificial e.g. HashSet::insert demonstrates that it returns a bool via an assert_eq, you have to figure out how cool and useful that is (then gripe that other langages don’t give this info) separately.


Even uninteresting examples are absolutely crucial. I've taught Rust to many, many people, and one of the things that new users rave about is how the docs provide an executable example of every API, no matter how trivial. This especially matters for highly generic functions (which are very common in libstd), where the signature is extremely imposing but the usage is surprisingly simple.


Cannot agree hard enough. Nothing is more deeply infuriating than api documentation that just expects the reader to understand what the author means. The trivial examples of everything means I never feel like I’m guessing when it comes to rust’s standard library. I dearly love working with Python and it’s many included batteries but plenty of the most complex and by extension powerful parts of the Python standard library need the kind of “show me how to do everything this is capable of” type example documentation that Rust uses. Last notable one for me was the documentation about changing stopitetation to an explicit error, and how the behaviour differed pre and post change. It took me far to long to work out what changes I needed for some library code to be updated because the documentation demonstrates a few good examples but does not cover all permutations of the behaviour they changed. It’s a low level feature so obviously they can’t show everything it can be used to do but they should have at least tried to cover all the different fundamental behaviours of the code. This is something the community are doing better with now, in part because of the excellent example the rust community is setting for documentation of a programming language.


I'm so glad to hear this.

My guiding principle for the absolute minimum of API documentation is "If I read the documentation and want to use the thing I read, I should be able to copy/paste something from right there to get started with."

This isn't perfect (trait implementations...) but it's nice to see that it's been as helpful as I hoped it would be.


Plus in Rust, the examples are also unit tests. So you can do TDD and flesh out the documentation while you're doing it.


if you have better example suggestions, you can easily make a pull requests with them.


I feel like the pace of Rust language evolution slowed down significantly after the 2018 edition and the work on async shortly thereafter. Most of the more recent language changes feel like pretty minor ergonomic improvements, things which always should have worked. I suppose we got const functions (can be evaluated at compile time), and const generics (allow you define fixed-length vectors for size N). But those features are well established in other languages and they don't interact much with anything else. And I'm sure I'm forgetting a few things, but that's sort of my point—subjectively, not a lot has changed for me recently.

What I have seen is a lot of good work in the larger ecosystem. And the tooling continues to improve.


I often see people complaining how bloated or large the language is, but I never see specifics. As someone who started learning and using Rust at the beginning of this year I was surprised to find out how simple the language is given its reputation on forums. What makes you feel the language is becoming too large, where is the feature creep, and where is the complexity you're talking about? Are you talking about the stdlib or language features?


Some people (including me) felt how async was added was worrying.

Adding ".await" means when I teach Rust we now need to say "x.y is member access. Unless y is 'await'. Then it's something totally different". That's the type of strange rule that C++ has, and if you gather enough of them, languages become very hard to teach.

However, async seems to be the only big language feature which effected many things which has been added.


.await is a postfix keyword - it effectively means "crazy control-flow (monadic) magic is happening here". "?" for failure handling is another bit of postfix syntax, that means something very similar. A good IDE will show it with a different highlight, so that it will never be confused for a struct member or method call.

This stuff was discussed by the community for a long time - bikeshedding about syntax is a well-known "trap" in programming language design. It has turned out to be (IMHO) reasonably intuitive, and preferable to the alternatives.


My biggest problem with await is it's very non-obvious if you don't know to expect.

Seeing a '?' is obviously a "new thing", so people go look up what it is (in practice, I would expect any Rust programmer to learn '?' really early, but if they somehow miss learning it, they will know to go look it up).

I've seen beginners assume they were "missing the await member". Of course, once you know it's something new you can learn it. I would have prefered something like .!await, just to make clear it's a "new thing".


Isn't "?" just a sugar for something like the following? That's how I think about it in my mind at least.

  // with "?"
  let v = x?;

  // without "?"
  let v = match x {
    Ok(o) => Ok(o),
    Err(e) => return Err(e), // exit current scope due to the return
  }.unwrap();
That feels like something that could be done with a macro.


It's more like

  let v = match x {
    Ok(o) => o,
    Err(e) => return Err(e.into()),
  };
> That feels like something that could be done with a macro.

Indeed. It used to be a macro called try!.


Ah, thanks for the correction, that's better yes


Yes, that's control flow magic. It was prototyped with a macro, but failure handling comes up all the time in practical programming, and it's important to make it as ergonomic as possible.


I see. I think reading your initial comment I took issue with the hyperbole "crazy control-flow (monadic) magic is happening here".

But yes it is a hidden control flow, and taking in account hidden control flows is inherently more complicated (or at least has a steeper learning curve).


That's a fair point. I haven't touched async yet but I've seen lot of discussions regarding "await" and that seems to create a good amount of confusion. Still we are multiple magnitude away from the level of complexity C++ has.


Yeah, the await syntax is just bizarre. One of the worst eyesores of any languages I've personally encountered.

An await macro or function would have sufficed but because Rust is still mainly a hipster language with a hipster community, they had to choose a hipster syntax after years of bikeshedding about how to make it absolutely perfect.


Prefix syntax has drawbacks that were constantly pointed out in that long discussion. In particular, it doesn't compose well in practical scenarios. .await just 'flows' better and in a more intuituve way.


Completely agree. I've used it at work now for about a year and the postfix notation flows perfectly with more intricate usages of futures. Especially with the sense that you construct one, then decide when to await it, or await a collection or whatever. Following the rust style of immutable variables and chaining function calls.

You can even await the same future multiple times in a select statement keeping it executing a bit further each time until it returns, if you do it by mutable reference. Really quite magic.

Now we just need async closures and some nice async style iterators. Something like FuturesOrdered or even FuturesUnordered in an inline iterator style allowing efficient nice composability. Without any of the pitfalls and gotchas those two currently have.

I think that might be what throws many people off? The regular style of method chaining and having the cold futures just be a dead piece of memory you can pass around until actually passed to the runtime?


> An await macro or function would have sufficed

We tried, and it literally did not suffice.


Works in other languages fine.


Different languages have different semantics. The challenges here are related to the ways Rust works specifically, as well as its goals.


Complexity is a death by a thousand cuts issue. I suspect most people complaining are going to have a hard time enumerating the many small sources of complexity they encountered.


Rust isn't a complex language by the standards of languages like C++. Complexity arises by features that work together in surprising ways. Rust has a medium-large amount of features (similar to Python (though obviously with a more imposing learning curve than Python)), but those features tend to compose very well, which keeps complexity from ballooning.


It is true that Rust is competing most directly with C++, but "less complex than C++" might be a true statement about every single language in existence that has more than a dozen professional users.


Kind of, Python, C#, Java have enough stuff on language + standard library to compete with C++.

A pub quizz with them would be just as fun.


I personally think those are all nowhere close. There are like ten different ways to initialize values in C++ and they all have slight differences.


Believe me, C# 10, Java 17 and Python 3.7, including standard library and runtimes across 25 - 30 years, have plenty of question material.


Rust doesn't reuse concepts well. The different capabilities and subsystems are all build from disjoint building blocks, which you could call modular in a sense, but it doesn't make them easy to use, learn, or joyful.

The module system, the macro system(s), the core language, the borrow checker. It's all different micro-languages without a shared foundation.

I think it's easier to when you compare Rust to simpler languages like Carp or Zig.

Carp due to its homoiconicity and lisp heritage allows you to write macros in regular old Carp. Zig doesn't really have Macros, but comptime (compile time) code evaluation, which results in something with a lot of the benefits of a macro system without the drawback of unreadable DSLs, because it too is plain old Zig annotated with `comptime`. Zigs module system is build on Struct name-spacing, so if you know Structs, you know the module system. Its build system is also build on Zig code.

My guess is that Rusts origins are partially to be blamed for this, the web is build the same way, disjoint standards that are developed by different groups of people. It's just that just like the web, the sum of the parts is less elegant and usable than each constituent.


Serious question about Zig’s comptime - isn’t that just like Rust’s const fn, except every function is implicitly opted in to being const?

Where this could be a problem - I write a comptime function, only using other functions that I’ve verified can be executed at compile time. But now the implementation details of those functions (that they’re comptime) has leaked to their definition. Now a change to the impl of those functions could break my code, without the authors of those functions realising it.

Perhaps this is not a problem in practice?


Kinda, but much more than that and the ergonomics are quite different as the entire language is basically available. For example in Zigs comptime, types are first class citizens which can be queried and operated on. This gives you generics without a lot of type system magic, and even const generics over arbitrary types. All without a macro system or Turing-Complete type checking (similar in flavour to the DeBruijn criterion: the comptime code/higher order proof system is turing complete but the type/core checking is straight-forward).

And yes the problem you describe could exists, but I've not encountered anything like it in practice. But the idea you had there captures the difference between Zigs and Rusts type-system/generics quite nicely:

> Rust tries to proof universally qualified correctness and behaviour of code, i.e. regardless of its context, while zig only proofs you the correctness of specific instantiations.

While this may sound like a bug, I'd argue that it's a feature, as it's YAGNI applied at a type level, and for example allows you to do things like:

  switch (builtin.target.cpu.arch) {
    .x86_64 => //do intel stuff
    .aarch64 => //do arm stuff
    else => @panic("unknown arch!");
  }

With the switch arms that don't apply simply being ignored and never type checked. This allows you to use a basic language construct where C requires a preprocessor and Rust requires macros or compiler magic.


The Rust solution for your arch variation specifically is hardly onerous, and does just the same, ignoring the code in not-matching branches:

  #[cfg(target_arch = "x86_64")]
  …

  #[cfg(target_arch = "aarch64")]
  …

  #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
  compile_error!("unknown arch!");
(If you got to much more complex cfg branches, cfg-if could be worthwhile, which lets you write `cfg_if! { if #[cfg(…)] { … } else if #[cfg(…)] { … } else { … } }`. But for only a few simple ones, I prefer to keep it out.)


Yes, it can happen. In practice is not a big deal because the kind of stuff that you would want to run at comptime is pretty much all logic that manipulates its inputs without other side-effects, but one could for example add logging to a function and break its ability to be run at comptime (Zig might add in the future ways of solving this problem).

I would say that more in general the problem between public interface vs implementation details is much bigger than any type system and requires humans to negotiate what should be considered part of the public interface through other means (eg: tests, comments). Comptime is one example, another is ABI stability (eg the layout of a struct, or just its size), another could be speed or memory consumption.

Zig doesn't have an official package manager yet, we'll see what happens once we get one and people in the community have to start communicating stability guarantees to their users.


The problem with that is in large parts that Haskell 98 is very outdated, and so relatively basic and absolutely useful extensions are in the same pot as all the experimental stuff.

Haskell Prime, essentially the Haskell 98 successor, is supposed to fix that. The first thing I do in almost any Haskell project is enable a bunch of extensions that I consider absolutely essential[1]. Most or all of those should likely be incorporated into the new standard, and then the truly experimental stuff stands out as experimental again.

Unfortunately it seems that Haskell Prime efforts have slowed down, despite a very active Haskell community in total. I have not looked into details there, though.

[1] For example ScopedTypeVariables, where it's hard to imagine for me at least why this would not be the default.


I think the GHC2021 group of blessed extensions provides what you want.

https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/cont...


That's indeed useful and something that I didn't know about, thank you!


ScopedTypeVariables by default! Excellent.


Out of curiosity, why do you find ScopedTypeVariables essential? I've written a fair amount of Haskell code and never once needed it.


Here's some explanation (not by me, found through search): https://blog.ocharles.org.uk/guest-posts/2014-12-20-scoped-t...

And among other things, it also enables pattern signatures.

The official docs at https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/scop... are generally worth a read, they start out with an example of what lexically scoped type variables allow, and follow with the design principles for the extension.


They’re useful on occasion, but don’t seem anywhere close to essential.


GHC seems to be more of a platform for crafting your own language than rust. Yes, rust nightly has experimental features that can enabled, but they seem to have gone through more vetting and design, whereas in GHC the features seem to be much more exploratory, or more explicitly, research oriented. It seems as though every contemporary haskell program is written in a different language, though rust at least, always has stable, which seems a much more sensible default than GHC's.


> GHC seems to be more of a platform for crafting your own language than rust.

It’s always been that tho, one of the motivations behind Haskell was to have a unified basis for FP language research: at the time (late 80s) there were a dozen half-assed half-implemented languages in the space, and the main and most stable platform (Miranda) was proprietary software.


Alas I had fun with rust and made some small apps but as I got deeper I just got scared off by the learning curve. I'm kind of over the hump with c++, javascript and python and I just couldn't do it again. Maybe I will revisit in a few years if it actually slows down.


The language evolution speed has nothing whatsoever to do with the learning curve - there's like two major features a year, one of which is only for advanced users. The rolling release cycle just means the tiny incremental improvements arrive sooner. The learning curve has been in place since 1.0 and it only gets harder the more times you give up.


> language evolution speed has nothing whatsoever to do with the learning curve

I don't think that's true at all. Little by little, ergonomic changes make it in, that are actually quality of life improvements for the end user. Better error messages, smarter faster compiler, better idioms etc. These are all small, but they add up. For someone coming into the language cold, it can be the difference between a terrible experience and a decent one. No language was born perfect, so let's not pretend Rust is there, or even close.


Rust keeps making small usability improvements all the time, but the major improvements have already landed in the 2018 edition (smarter borrow checker, modules syntax, forgiving match patterns).


I think everyone in this thread can be in agreement:

* there are language and tooling improvements all the time, that make learning the language easier

* waiting to learn the language can make it easier due to the above

* if you learn Rust today the amount of things you need to learn going forward are few to none, the evolution of the language doesn't make your old knowledge useless


To be honest, and maybe I'm just an outlier... As someone who uses Haskell for most of my personal stuff (sadly, not for work), I really don't mind the complexity. Haskell98 is... nice, at best, but it lacks a lot for me to be truly pleasant. GHC Haskell with extensions however I find a pleasure to use, and I've always felt like the complexity was well placed, right where I wanted it or needed it. Rust is also nice, but for me personally the extra features are just making it better, not worse.


No worries, Rust has a looong way to go before they reach C++ levels. And the editions system even makes it feasible to pursue some ex-post simplification, though that requires a number of years to complete and cross-linking across editions must be preserved regardless.


I get the same feeling, Rust seems to be going down the path of "#[feature]" collection.


Rust feature flags aren't the same as Haskell feature flags. In Haskell you design your own programming language by selecting which extensions to enable. In Rust, feature flags only exist on the unstable nightly compiler and either get folded into the language proper or deprecated and dropped entirely. It's not a combinatorial explosion of interacting extensions, it's a single base for everyone that grows over time.



Oh, those features, you are talking about stuff that is included/excluded in libraries. Those have nothing to do with compiler extensions, they don't change the language.


Indeed, perhaps it was bad to name this (er) feature of Cargo with the word "features", since it invites conflation with the unstable #[feature] attribute of nightly Rust, but it has nothing to do with the language.


It shares that as well as horrendous compile times with Swift.


The irony being that while C++ is known for its compile times, the ecosystem relience on binary libraries makes it much more tolerable.

Microsoft is also shipping pre-compiled projections for Rust/WinRT.

Then we have examples like image, that compile rayon twice, with different versions, because we just love to watch third party crates being compiled.

However I should also add that compile times have improved greatly, my travel netbook can finally handle small Rust projects without killing the battery.


C++ binary libraries are a disaster. At least Rust is honest and tells you to just fall back to the C ABI for interop, and rebuild high-level abstractions around it in code that's built with the project - much like a 'header-only library' in C++.


I beg to differ, and until Rust community acknowledges they are relevant, there are industry domains where C++ will keep its dominance.


Take a look at the C++ community discussion around the feasibility of "ABI breaks". The C++ community is acknowledging the issues, and how they're getting in the way of continued "dominance" in many sectors.


I am fully aware of them, a vocal minority that only cares about FOSS libs.

Why do you think Apple has spent such a big effort making Swift work for shipping binary libraries?

Most devs would just stick with Objective-C, C and C++ otherwise.


> Microsoft is also shipping pre-compiled projections for Rust/WinRT.

Eh, sort of. They're basically shipping the Rust equivalent of C header files and import libraries. Whereas before they would parse metadata in a build script which would then generate the Rust code on the fly (which was hell for a number of reasons). And the installed Windows SDK was used for the import libraries.


Nope, I was speaking about this,

https://github.com/microsoft/windows-rs/tree/23ff38bbbf46fb5...

Apparently since last November they decided to replace it with another approach, so my information is outdated.


I have some time between contracts and I've found myself learning rust.

Pros:

- Sum types. I am an OO apologist, but trying to use classes in C++ is an exercise in frustration. Sum types map very well to union types and are a better fit for systems programming.

- Unit tests built right into the language - it seems like a small thing but it's a hassle in most languages to choose a library, set it up etc.

- The above, combined with cargo-watch [0]. With the right flags, you hit save, and your tests all run. It's a god-send.

- Ecosystem is pretty big. I can find most things I need.

- Discord channel is nice. I was put off a bit by the Rust Evangelism Strikeforce back in the day, but so far everyone is pretty chill.

- Options & Results in the standard library. All languages should have this

Cons:

- I find it hard to transfer knowledge of C to rust, because they use different terminology.

- Docs can be confusing to read because every method on collections like `map` or `filter` returns its own Trait. People have explained why this is to me a couple of times but I still haven't gotten it through my head.

- You still have to think about memory and pointers. Not always a bad thing, but it is an extra dimension when solving a problem.

Overall I'm powering through. I'm hoping to get to a point where Rust is an obvious choice for anything that involves finer control of memory.

[0] https://github.com/watchexec/cargo-watch


As someone with 20 years of C++ experience, in industries from everything from real-time systems through to low-level HPC graphics on CPU/GPU (currently in VFX), I really don't understand the hatred for OO programming, and I must be either missing something, or being lucky with the codebases I'm working on...

It's a tool for encapsulation: you can get into trouble with it, but I'd argue the same is possible with many things - it's how well you use it. You can easily use state composition in C++ if you want, and generally (multiple inheritance can cause issues in some cases) you can use interface classes as well.

And as someone who's been learning Rust for the past 6+ months, I've found that of the three new projects I started which I started in Rust instead of C++/Python over the past 4 months, Composition actually worked quite less well (it's quite verbose due to all the plumbing needed to connect things up) than if I could have used OO interitance in many situations where I wanted specialisation - i.e. hierarchy behaviour traits that had both common shared state and functionality AND specialised state and functionality. Thankfully Traits can at least have default implementations - if not, things would have been a bit worse.

To be clear: there's a lot to like in Rust though.


Encapsulation is just another way of saying correctly used visibility modifiers. It doesn't mean the state has to be inseparable from the behavior, and its role is semantically fulfilled in Rust by modules. And IME issues with OO feeling like the better role tend to be people attempting to solve all the problems with one feature like OO lets you do, shying away from doing it with multiple features even though they're really multiple concerns. E.g. for common behavior manipulating common state among several local structs, a macro is what you'd use.


The 'hate' is reserved for implementation inheritance, which has its well-known drawbacks (research the "fragile base class problem") - basically, it introduces complex long-range coupling throughout inheritance hierarchies that makes it way too hard, or even impossible, to evolve code over time. Everything else is very much doable in Rust.


The criticism of OO is more Java and Gang of 4 related than anything.

Two things get the enterprise devs of the mid 2000s going:

Badmouthing Oracle. And complaining about refactoring someone's mess of an abstract factory.

Especially I would say since microkernels just became incredibly widespread After Docker. Encapsulation is just not as necessary as it used to be.

In C++ the whole encapsulated structs thingo works fine.

It's there for when you need it, and you don't need it when you don't.

Gang of 4-esque programming is okay when it's necessary. Sometimes you are making something with a 100 different buttons and you just gotta do it that way.

However, for every project that needs all those factories and such, there's probably 5-10 where straight procedural/functional programming is perfectly fine.

Or in the case of many data oriented applications, or when formal verification is needed, probably just straight better.

Just do your abstraction with subroutine signatures and scope.


One of the pieces of OO _inheritance_ I deeply miss in Rust is the ability to subclass a library class, override *one* function, and retain all the other functionality. Yesterday, I needed to tweak the behavior of one function on actix-identity's cookie and my option seemed to be to wrapper the original object and write the same interface for the entire object, passing through every function except the one I wanted to override. Am I a sinner for wanting inheritance yesterday? Probably, but I had to write so much boilerplate to achieve my tiny override.


You don't necessarily need inheritance. Kotlin for example has a feature wherein all that forwarding boilerplate you had to write is automated.

https://kotlinlang.org/docs/delegation.html


That sounds fantastic. It also sounds a bit like a vtable :-D


I guess one way would be via delegation, similar to how COM does it.

I bet with a couple of macros it would be possible to automate what languages on Windows can somehow do magically with COM interfaces.


You don't need any macros, it can be accomplished with the trait system[1], either manually or through auto-deref. Some of the boilerplate could be generalized with a derive proc-macro or a macro-by-example call but it is not absolutely necessary.

[1]: https://play.rust-lang.org/?version=stable&mode=debug&editio...


Thank you so much for this.


> As someone with 20 years of C++ experience... I really don't understand the hatred for OO programming

Well, where should I begin:

    std::cout << "Hello world";
Is just a nice way of doing things...

As the other commenter said, it's not so much OO, but more GoF and how the 2000's OO went.

Please tell me why any basic library adds 3 or 4 levels of inheritance just to do something basic like vector or array. "Oh but this is to make things more generic" and yet nobody uses all that generic stuff. STL is often replaced by more "serious" users.

C++ (and Java) are 2nd systems syndrome gone to 11

I've just taken a look at the Vector implementation at my current system and it's an exercise in frustration. Meanwhile I can understand most of this https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#400


What does std::cout << has anything to do with OOP? It is simply operator overloading.

Where is the level of indirection in std::vector implementations? With templates, c++ really doesn’t use virtual dispatch all that much.


> has anything to do with OOP? It is simply operator overloading

It is an example of how they fumbled the implementation of APIs, because this one has very poor usability.

> With templates, c++ really doesn’t use virtual dispatch all that much.

Good, but try to understand why your multiple-inherited vector is not compiling by reading a 3 line error message.


I wasn't criticising OO. I was talking about how much of a square peg in a round hole it felt - for me - to do OO in C++.


> every method on collections like `map` or `filter`

I think you're remembering the various iterator adaptors, but they aren't methods on collections, they work on Iterators as their name implies. Somebody else explained why these methods can't all just return "Iterator" (that isn't a type) but just thought I'd mention you won't find map and filter in Rust's Vec or HashMap types, those methods live in the Iterator trait.


`iterator.map(…)` must return a new wrapper type, because it needs to store the closure somewhere, so it returns

    struct Map { closure, original_iterator }
This fact could have been hidden by making these methods return `impl Iterator`, but it would be strictly less useful/performant in case you needed to store the iterator somewhere, because then you couldn't name the actual type, and would need to work with an abstract one.

But I do agree that the way documentation presents traits and their implementations can be overwhelming, especially the Iterator which is a pretty large trait.


> because then you couldn't name the actual type

I'm sure you know this, but `type Alias = impl Trait;` is on its way which would make naming those possible.


Although that's true, and potentially useful as a feature (not sure I want it, but pretty sure I wouldn't be angry if it was added)..

I don't think that's what your parent was talking about when they say "couldn't name the actual type".

They're saying, suppose I have a function that says it return an Iterator and I realise ah, it's not really returning an Iterator, but some subtype of Iterator - or, in Rust where subtypes don't exist, a type which merely implements Iterator. I now can't talk about the actual type being returned, because that's hidden from me, and it needn't be.


For posterity, this is Rust RFC 2515 type_alias_impl_trait.


They return their own type, all of which implement a common trait, because traits are not types, and there's two options for representing 'any type that implements this trait', one of which can't be returned without allocating it (dyn), and the other of which can't be used in trait methods (impl). As a (frankly minimal in my opinion) effort to make this less weird to look at, the docs now have a (nearly invisible) 'notable traits' hoverable, which tells you what types implement Iterator and that anything other than them implementing Iterator is not very important.


Re: knowledge transfer. Why do you expect your C knowledge to transfer to Rust? Let me tell you clearly: it doesn't. It's not because Rust uses different terminology. Rather, Rust uses different terminology because underlying concept is different, so using same terminology would only lead to confusion.

I found this to be the case: Rust is equally hard to learn, for C programmers and for Java programmers. But C programmers get frustrated more, because while Java programmers don't expect their knowledge to transfer, C programmers have unrealistic and unjustified expectation of knowledge transfer. Actual learning curve is same, just expectations differ.

I wrote about this in 2016: https://sanxiyn.blogspot.com/2016/06/problem-in-rust-adoptio....


I expected (or should I say hoped) C knowledge would transfer because - that's my main point of reference for a programming language where you care about memory.

I don't think there's anything particularly unusual about it - were I to seriously learn haskell, I'd hope whatever knowledge I had of Ocaml would put me in a good position.

Your blog was spot on - with the caveat that people who know C++ can easily "learn" stuff like Java and C# but tend to write very C++ flavoured Java and C#.


That's not covered by the survey but I'm wondering how much of Rust usage is driven by crypto-currency projects. I'm personally completely convinced by the Rust language and the ecosystem, and decided to bet on it as my main tool for the next decade or so, but I'm also a bit worried that a lot of the money for Rust roles comes from crypto-currency projects (an industry I'm now very sceptical of given the amount of scam/bullshit we've seen during recent years). Not sure if my worries are warranted given my personal bias. Just something I have in mind.


To my knowledge, most of the people working on Rust, the project, are employed full time at Amazon, Facebook, Google, Microsoft etc. There are a few folks who benefit from sponsorship from some crypto firms but I think that’s the minority.

While it’s a legitimate concern that many jobs appear to be from the crypto industry, I wouldn’t worry too much. Whether they’re scams or not, the entire community benefits from the software they sponsor and open source.


Re: blockchain sponsorship. Minority, yes, but not without weight. For example, current Rust language team leader and library team leader are sponsored by blockchain projects.

See https://medium.com/concordium/the-devx-initiative-rust-ecosy... for details.


Perhaps I'm asking you to trust me, but I can stake my own reputation on the fact that neither Mara not Josh are in any way compromised by this sort of sponsorship. Both of them have been doing incredible work for years, and while I can't speak to Mara's financial situation, Josh gets sponsored by a ton of different companies to do Rust work (including my own, and we have nothing to do cryptocurrency).


Crypto is like the dotcom bubble. Lots of scams, lots of half finished (but well intentioned) crap, and a few projects that might survive into the future and become something useful beyond being a casino with constantly changing odds.

Rust is particularly good for crypto because 1) it is very efficient and 2) ownership semantics let you model things in a way that prevents many of the issues plaguing solidity and etherum.

There will be a crash though, and a lot of the money on Rust will evaporate, but I think this early push will ensure the language survives well into the future.


I fully agree, that's exactly what I'm seeing in the job market for Rust in switzerland. It's unfortunate, but I guess more traditional industries are firmly in the grip of Java etc.


Why would it be worrying? Lack of jobs outside cryptocurrency companies? Language features focused on crypto?


I found this surprising... 59% of respondents sounds huge!

"Rust can now safely be classified as a language used by people in professional settings. Of those respondents using Rust, 59% use it at least occasionally at work with 23% using Rust for the majority of their coding. This is a large increase over last year where only 42% of respondents used Rust at work."


I don't think this is entirely surprising. Rust isn't many people's first language. People who learn it, mostly do because they have become fed up with the unreliability (typically of C). This creates a bias towards people who are more experienced and have more organizational power. Also, language surveys tend to be biased towards power users which can shift the sample significantly. For example, the Julia survey from 2021 only had 25% Windows users, while Julia binaries are something like 70% windows.


Your comment about people with "more organizational power" may be an accurate reflection of things, but I don't think it's necessary to explain this increase in people using rust at work. It could be that more and more people are using rust for small ad-hoc scripts, which might have been written in python or java before. These small things might not require any organizational approval, but people might be more comfortable now using rust (either because their own skills in the language have improved, or because they feel more comfortable justifying the use of rust, even if they don't need to).


I think that's a genuine use of Rust for Real Work™. For example, Cloudflare went from using Rust for one project 3 years ago, to depending on Rust in core components and using it by default for almost all new development.


> Rust isn't many people's first language.

Has anyone actually tried to teach/learn Rust as a first programming language? People did it with C++ (and even C) at some point, is Rust that much more problematic? (And the attempt might even inform new convenience features: the proc macro system gives Rust a lot of inherent flexibility there.)


People have. In my opinion, it's a bad idea. I think that to appreciate Rust's design, you pretty much have to be familiar with the awfulness of memory leaks in C/C++ (and it helps if you have experience trying to make a program in a GCed language hit strict latency requirements). I think Rust's design is genius, but I think the first language you learn should be an easy language with a GC (there's enough hard parts of learning your first PL). The next step is to learn C (because it's beautiful but fatally flawed), and only after you have learned why manual allocs and frees suck, should you learn Rust.


The easiest way to conceptualize Rust's design at a basic level (suitable for first-time learners) is probably as a glorified functional language, where you initially pass everything by value (courtesy of .clone()) aside from shared immutable data (passed via shared references). Mutable borrowing can then be introduced next, followed by the "cell" patterns/constructs for shared mutable state. Not altogether trivial, but it seems like it could work. And the compiler would protect against many errors along the way, that bite C/C++ coders.


Rust is strict about ownership, which doesn't have equivalent in other popular languages. Users coming from GC languages are surprised Rust can't make things "live long enough". Users coming from OOP languages are surprised that Rust has on-stack objects without a layer of indirection. Users coming from C are surprised that references aren't like pointers.

So I think it would be interesting to teach users Rust's point of view first, before they learn the "misconceptions" from other languages.

But in practice something like JS is better, because students can make something engaging appear on screen before they lose patience.


> Users coming from GC languages are surprised Rust can't make things "live long enough".

If you really need a general 'long enough' strategy and can't just pick a sensible place to drop the object statically, that's what Rc<> and Arc<> provide - built from the ground up via refcounting.

> Users coming from C are surprised that references aren't like pointers.

For good reason. General "pointers" don't have a simple, compositional semantics that preserves modularity (Yes, I know about separation logic; that's not practically reasonable in a language like Rust - or C/C++ for that matter - that's not built around expressing complex logical invariants in code); references do. A piece of code that uses pointers in non-reference-like ways must be understood as a unit. Which is why Rust strives to reduce such code to a minimum, marked with a scary "unsafe" keyword.


I agree. I think Rust (or at least many tutorials of Rust) paper over ownership as something the compiler deals with for you but I think that's false. You have to think about memory and ownership. Only when I started using C++ where you have to think about the same things but without the static checking do I appreciate the ability to statically check and enforce things like moving and borrowing


> I think that to appreciate Rust's design

Why not take it for granted like you do for C vs ASM?


the C memory model kind of falls out naturally from technical constraints of hardware. the rust model comes from 60 years of accumulated pain of memory bugs, and a realization that humans are fundamentally incapable of correctly using the C memory model.


The Rust subreddit regularly gets posts from people learning Rust as a first programming language. I'd say about half of them have a good time of it, about half give up and are directed towards python. Plusses tend to be good learning resources, and a welcoming community (easy to ask questions). Negatives being the borrow checker and a steep learning curve.

I'd say Rust is quite a bit easier to learn than C++, while being a step up from Java and two steps up from Python or JavaScript.


That's an interesting statistic about Julia. Makes me curious what the stats would be for Rust.


I write a bit of Rust, but not for work, and I never heard about this survey. I think that's probably common - the more Rust you write, the more likely it is that you fill out the survey, so the sample is probably very biased towards people who work with it a lot (ie, professionally).

Or - you could describe that as biased, at least. Alternatively, maybe the intent of these language surveys is exactly to find out what committed power-users think. Either way, interpreting results from language surveys is tricky business.


I think it's true that surveys like this will skew towards more serious/dedicated practitioners, but in addition to professionals, the Rust community has also at various times attracted people who were excited about bleeding-edge things, or PLT/type-theory people, etc., and I think this survey probably does show a shift in the user base towards work-a-day users and away from these other groups.

(Or more succinctly: the absolute numbers are probably meaningless, but the trends are maybe worth watching.)


The self-selection bias effect is why the survey on isolation is not enough to derive meaning on its own. But, looking at the trends over time as the yearly survey is analyzed and compared with the previous ones is useful.


If you want more data, I've compiled statistics from crates.io:

https://lib.rs/stats


I'm curious about the methodology of this survey. The first thing I think about when reading survey results is the possibility of selection bias.


Ah yes these things are not scientific studies. Just read them as tech culture with diagrams and numbers.


The percentage of people using Rust continues to rise.

How was the sample selected?


Why, selfselected of course! How surprising that people who still chose to fill out a rust survey in 2021 increasingly use rust! ;-)

On topic, i’d like to try out rust, but can’t find good cause in my daily webdev needs.


Although I write mostly in Rust, when I have to do some web server side work, I use Go. Go was designed at Google for their server-side applications, and it's well-suited to that. All the expected libraries have seen very heavy use and are unlikely to have unexpected problems. Goroutines handle the job of both async and threads, simplifying concurrency. Rust is overkill for such work.

Rust is for complicated problems where both performance and safety matter. Web browsers. Databases. Operating systems. Industrial control. I'm writing a client for a virtual world in Rust. It's much easier to do complex concurrency in Rust than in C++.

Use the right tool for the job.


How's the compiler speed? I've been so burnt out on hobby programming on SwiftUI because of the horrendous long compilation times.

Makes me long for some Pascal. :)


The compiler itself is fine and its performance well managed, with weekly perf triage and efforts driven by profiling[1], but because adding dependencies is effortless and vetting them isn't, dependency trees tend to get large if not careful. In particular, widely used proc-macros (code transformations pulled by popular packages like serde, clap, tokio…) add very heavy dependencies (like syn) to the critical path. As a consequence, downloading and installing a tool from source is often a poor experience.

As far as development experience, cargo clippy / cargo check / rust-analyzer give you the feedback you need without involving codegen (except for any proc-macros in your dependency tree), and incremental compilation makes codegen faster after the first build. Work is also ongoing[2] to make debug-quality codegen faster.

Here is a quality article on the art of keeping a Rust project fast to build: https://matklad.github.io/2021/09/04/fast-rust-builds.html

The overall series on organizing a large project is worth reading as well: https://matklad.github.io/2021/09/05/Rust100k.html

[1]: https://nnethercote.github.io/2021/11/12/the-rust-compiler-h...

[2]: https://bjorn3.github.io/


It depends on what you're doing. Rust is not uniformly slow to compile, the slowness is associated to a few specific features like generics and macros. (Good generic code should delegate to a less-generic implementation as early as possible. Hopefully full "const" generics will soon make this feasible in more cases.)


IMO the other responses downplay it. Compile times are not good.


Rust is so good, I would switch from python to Rust in a moment if there was the right ecosystem for Data Science / AI stuff


> The next largest concern was that the language would become too complex (33%).

I'm also in this camp, although I would go further to say that Rust is already "too complex." Or maybe not. Go has already done an excellent job of being a very simple and effective language. Rust's complexity makes it very useful for some cool stuff. Like building DSL's.

But because of its complexity, Rust is not the language I would reach for in most cases when building almost anything pretty standard, like a basic web app backend. For that, I would choose Go over Rust every time. The reason being: the cognitive load of Go is far, far lower, and that is super important for maintainability and being able to collaborate with others.

Basically, in the Venn diagram of what Rust can do and what Go can do, I'd mostly use Rust only for what it can do well and Go can't. For example, a real time system that can't have GC overhead. Or sometimes I'll choose it anyway for my hobby projects, just 'cuz I think it's cool and want to use it. But if I put on my pragmatism/business hat and want to build anything seriously, that's the way it will go.

Take that for what it's worth since I'm very new to Rust (and I quite like it actually!). Although I have a lot of experience with a lot of other languages including C/C++, Java, Go, Perl, JS/TS, Python, and more. Rust is up there as one of the more complex languages I've used. I've really noticed it on the learning curve so far. Reminds me a lot of Scala, actually.

The onboarding experience of Go vs Rust is night and day. You can legitimately go from reading "A tour of Go" to understanding most Go projects within a day (if you're already an experienced programmer). And it's not because Rust is lacking good learning resources. It has amazing docs and so many amazing free resources. I'm honestly enjoying and learning a lot about it rather quickly, I think. But it's still taking a long time and I can see I'm in for a ride and will be going "oh wtf is that" in Rust source code for a very long time!


Pity that it is hard to find Rust jobs outside blockchain.


Rust is a terribly slow language to write in, especially if you’re trying to fight it in any way - because you‘ll lose.

It’s verbose and quite ugly as it tries to appeal to C family programmers while being expression and pattern based.

When trying to resolve ownership issues with closures the first time, you‘ll be doubting whether Rust is in fact a language or just a sick elaborate joke that tries to mock you for even considering to use it.

But with every concept learned you feel accomplished and start to develop Stockholm syndrome. The Rust compiler beats you to pieces and puts you together again.

As a new programmer, you rise from the ashes of your past inadequacies and delusions:

„Rust is actually a pretty productive language.“

On a more serious note: there is a book „Programming Rust“ and likely others that help with a structured introduction to the language, which I feel is a warranted approach, especially if the memory management concepts seem alien to you.


> When trying to resolve ownership issues

aka fix provably buggy code before it makes it to production?


I was trying to joke about the experience of learning the language rather than making an educated assessment of it.


I feel like some others aren't seeing the humour in your comment. Or maybe I'm just weird. Orr maybe I'm new enough to Rust still that I don't get offended. Anyways, you got a laugh from me at least!


Yeah! It’s a language that’s highly praised for good reason. But it’s also quite challenging to grasp some of the unique concepts to a degree where humor is the only viable self defense!


Lovely Survey :)




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: