Hacker News new | ask | show | jobs
by amalcon 2616 days ago
The author says that this is "why Rust is interesting". I've done a little bit with Rust -- no production code, but some simulations and things like that. While compile time memory safety was the first thing to interest me in Rust, I don't even think it's the primary selling point anymore. The selling point to me is that nearly everything behaves in predictable ways.

E.g. since immutable references are the default, you immediately know whether or not a call will modify its argument. E.g. the existence of traits and compiler warnings for style mean that method naming conventions are incentivized, because implementing a trait usually gives you a lot for free. Even performance characteristics are very predictable, a statement which I can only otherwise make about C and assembly (and those are not predictable at all in other ways).

Yes, the memory safety does play into this. It's much more than that, though: memory safety is just one factor in a kind of pervasive predictability that the language encourages through its very design.

6 comments

The biggest selling point for Rust is a non-obvious one and one that is hard to "sell" with screenshots: refactoring. Despite having few tools for automatic refactoring, manual refactoring of large Rust codebases is a breeze: change the portion of code you care about, follow the compiler's complaints and by the end you're likely to have a codebase in a good state. I wouldn't be able to go back to a dynamic language after using Rust for so long, I'd be in constant panic about changing the smallest thing. I equate it to the same discomfort I feel when getting on a car with no seatbelts. I'm just waiting on the day when I can plug the change I want to do to rustfix and let it figure it out, with the help from the compiler.
> refactoring of large Rust codebases is a breeze: change the portion of code you care about, follow the compiler's complaints

At my $DAYJOB I write a lot of Java, and modern full-featured IDE's for Java like IntelliJ are absolutely awersome for refactoring. Most common refactorings are fully automated, and many more complex things are very easy to do by combinding some of the base refactorings.

I really like writing Rust in side projects, but after getting used to the phenomenal support refactoring support in Java, having to follow the compilers diagnostics feels very primitive.

Jetbrains' refactoring tools have always been top tier. For years resharper was absolutely essential for C# development because visual studio just lacked good refactoring. VS has been catching up and has mostly caught up in recent editions but I doubt that would have happened if not for MS being able to see just how popular resharper is.

I'd hope that as Rust grows in popularity the tooling will come from that so I'd keep an eye on the intelliJ rust plugin or rider support for rust because as you say, it's really difficult to go from a day job where for example promoting a local variable to a parameter (with replacement at the call sites) just works to one where you actually have to think about manual refactoring.

One reason why I'm optimistic about Rust is because the team not only explicitly recognizes the need for advanced tooling (such as IDEs), but owns critical parts of the underlying infrastructure, such as RLS. If you want a language to have quality tooling, it needs to be designed for that, and there's no better forcing function for that than having to write that tooling yourself, or at least having someone who does on the same team, in constant communication.
> I'd hope that as Rust grows in popularity the tooling will come from that ...

Patches are welcome! https://areweideyet.com/

The Rust plug-in, is already quite nice, and getting better all the time. I use it from CLion, since that has integrated debuging support.
You are mixing "fancy tools for mature language" with core capabilities of another (that will enable even better fancy refactoring tools in future - tools that can make more complex refactoring tasks fully automated). If anything, the fact that what used to be an external tool has migrated to core feature in Rust is a testament to how forward looking the language is. Imagine what that will enable in tools to come!
I'm not implying that Rust should have these yet; I am fully aware that the situation for Java is different due to serious and long efforts in developing great refactoring tools.

The point I was trying to make is that the view that Rust is great for refactoring depends heavily on what one is used to. For example, as compared to any dynamically typed language, a strongly typed language will be better for refactoring.

Writing refactorings that work reliably is very complex, and I'm not sure if it is practically possible to write the same kinds of refactorings that Java has for Rust. Two of my favourite refactorings in IntelliJ are extract method (with automatic duplication finding) and inline method/expression. I think that such refactorings are a lot more complex to do reliably in Rust due to ownership and borrowing rules, unnameable types, and so on.

I fully expect rustfix to gain refactoring capabilities, even if haphazardly bolted on. Things like changing an owned field to become a borrow requires a lot of trivial changes that can be automated away (other than making sure the field been borrowed has an appropriate lifetime, it course) that for the most part rustc already emits as structured suggestions that other tools can use.
IntelliJ plugin for Rust can do some refactoring (renaming functions and variables - it's all I use and remember).
For Rust development I use CLion with the Rust plugin, and it is getting better and better all the time.

It is interesting seeing the difference in peoples expectations on what an IDE can and should be able to do for you depending on what they are used to working with.

I'm really glad to see that there is a huge resurgence in support for statically typed languages in mainstream programming. I always felt that this was somewhat inevitable, but the tide of opinion was against it for a while. I completely agree, and the inverse situation is true too. If you're used to statically typed languages, working with a dynamically typed language can be hellish if your codebase is suitably complex! And by suitably complex I mean more than >500LOC. ( That's not a typo, the omission of the 'K' is intentional. )
I'd love your thoughts on this, my guess is it's because of ergonomics improvements. Specifically, inferred types. This middle-ground lets you have much of the ergonomics of a dynamic language but with the safety of a static one. You may have to hint it from time to time, but for the most part (99%+) Rust guesses the types of everything I do day to day, and when it doesn't know, it ... asks.
Inferred typing is just a feature of statically typed languages. Static typing just refers to the type of a variable being known at compile-time. Type inference is the ability of the compiler to infer the variable's type from the context of its declaration. It doesn't mean that there's any loss of safety at all, it's just a matter of syntax.
Yep, exactly; I was suggesting that the move in modern languages towards inferred typing is what makes statically typed languages pleasant to work in, which has lead to their return to popularity. Sorry if I wasn't clear!
Oh, pardon me. I re-read your post and it makes more sense to me now! Maybe that plays a role. I more attribute this, somewhat in jest, to enough time having elapsed since the renaissance of dynamically typed languages began for developers to have gotten sick of maintaining codebases built in them. I also, very cynically, think that there's a very contrarian and competitive streak running through the development community which drives developers to always seek to move against the majority. Cultivating a kind of heroic self-assertion in the process. Think, for example, of the resurgence of interest in functional programming and the aggressive proselytisation on its behalf. In defence of my polemic assertion here, I have somewhat cultivated this idea around myself and my own shortcomings. Also, even when I program in languages featuring type inference I usually mandate that my team use explicit type declarations for the sake of clear declaration of intent and better tooling support, that's just one opinion there though.
In some sense. I mean, type inference is not new. But the languages that really brought static typing to the masses didn’t use it, or only did deduction, so it is “new” to a lot of programmers.

I do think that there’s a relationship between power and usefulness, but more power isn’t always better. I’d rather use Ruby than Java 1.5, but I’d rather use Rust than Ruby. YMMV.

It's kind of sad to me that (almost) complete type inference has been around since the [70s](https://en.wikipedia.org/wiki/Hindley–Milner_type_system) and it's still not mainstream. (unless you consider F# or OCaml mainstream languages)
Type annotations at the signature level are documentation, so I'm not so sure if global type inference is really better than local type inference. Also HM type inference doesn't play nice with type systems with subtyping or method overloading.
“change the portion of code you care about, follow the compiler's complaints and by the end you're likely to have a codebase in a good state.”

That has always been my refactoring algorithm with C++, C# of TypeScript now. I know a lot of smart people using dynamic languages but I always prefer to lean on the compiler to tell me what needs to be changed.

> I wouldn't be able to go back to a dynamic language after using Rust for so long, I'd be in constant panic about changing the smallest thing.

As someone who has been working mainly in Rust for about a year and is now starting to pick up Python, this is huge! I pretty much never write Python that isn't explicitly typed thanks to how Rust changed me as a programmer.

Same. I think Rust has been the biggest thing for me in terms of growth as an engineer in recent memory, and I've worked across the stack from HDLs to embedded to mobile to desktop to server over the course of my career.
I think the question was what the biggest selling point is for those who already do e.g. C++, not for those using dynamic languages like Python.
Both questions are important, though. The Rust community is in a very compelling position, in being able to appeal to both the C/C++/'system programming' and the Python/Ruby/etc/'high-level application programming' dev communities.
What I was trying to say was that ease of rafactoring compared to a dynamic language like Python isn't omitted because it's "non-obvious". Rather, it's in fact quite obvious, and simply omitted because it's answering a different question than the one that was asked. Robust refactoring isn't Rust-specific or even new. It's always been the selling point of many statically typed languages, like C++, D, Java, etc.
I mentioned Python because it sits in the other extreme, but the combination of pattern matching, strong types, type inference and ergonomic combinators on the standard library makes the experience much nicer than, for example, Scala. Robust refactoring isn't new. Rust isn't novel. It's just well put together because it had the benefit of hindsight and being able to consider how different advanced features fit together without having to abide by backwards compatibility until recently. Refactoring a single threaded process that operates over a vector can be a single line code change, and the compiler is capable of complaining about data races by leveraging the type system and lifetime analysis.
Much nicer than scala? I don't see how you can claim that if you've touched futures in both languages.

Rust is a nice language for threaded programming, but the async situation is a trainwreck 4 years in the making.

I think you'd be surprised, Rust has seen a lot of adoption & interest from the dynamic languages crowd.
Go and Rust killed my interest in writing Python code. A paradigm shift worth losing amazing libraries and frameworks like SQLalchemy and Django is rare, but I believe we are here (and have been for a while.)
> Go and Rust killed my interest in writing Python code.

Strange to see Go suddenly brought in to support Rust like this. Was it Go that killed said interest or Rust? Why is Go relevant here?

For the same reasons: it offers a strong alternative to C/C++ with memory safety. Often I want performance like C++ but cleaner code and memory safety. Before recently, Python was a go-to when you didn't want to cut yourself on C++s sharp edges, even with it's disadvantages. The overlap isn't clean, but Go is strong for writing simple programs and glue layers, and Rust is strong for writing complex software where correctness and performance are both very important.

Python still has a fair bit of expressive power that Go and Rust would struggle to provide, but I think both can be compelling alternatives in different cases, and they offer a lot in exchange (such as, full type safety and improved performance.)

I realize Rust offers much more safety than Go, but both of them are eons ahead of C++ in this regard. When you're starting from nothing, any level of guarantees is a huge shift.

Go has garbage collection support, so it's definitely more convenient in some specialized domains than Rust - namely, those which inherently involve spaghetti-like allocation and "ownership" patterns that RC alone can't deal with very well. You wouldn't want to rewrite a typical LISP codebase in Rust, but with Go you could make it work and get good performance out of it.

(You could of course use a ECS-like pattern in Rust and end up with a half-baked reimplementation of a Go or LISP runtime, but the ergonomics would not be there.)

Another point is that using rust is great for products, but not so much for PoCs, since the compiler will complain about most ‘hacks’ to release early, or even refuse to compile.

I have not much experience with go, but my feeling is that it should be faster to have something working, and then if it’s worth it (e.g. if it needs high performance with concurrency), migrate to rust.

This is one of the big reasons I use TypeScript over plain JS as well, especially when combined with TSX for typesafe views.
Actually I got into rust because it is the only language that has both ADT/patten matching and a practical mindset/community. There is simply no alternative. I would even code front-end rust for the sake of this.
Reasonml also has adt and pattern matching
True, and swift. They are nice to work with too.
E.g. since immutable references are the default, you immediately know whether or not a call will modify its argument.

You do not, since the type of which an object is referenced could use interior mutability (e.g. RefCell). So, you only know if this is the case after inspecting the type.

Of course, the default in Rust is to use exterior mutability and in general, interior mutability is/should be avoided.

(I agree with the general thrust of your comment though.)

Rust's mutable/immutable is better thought of as exclusive/shared. But in any case, the interior mutability is not causing problems, because the compiler still largely enforces it's used correctly (e.g. no matter how deeply RefCell is hidden, code using it won't be able to share it with another thread, so you don't need to worry about getting a data race this way).
I fully agree with you, and actually I want to write a summary of those less-discussed features that have high productivity impact including the predictability you mentioned in the future.

Though, for the people who haven't explored Rust yet, I still think that focusing on the memory safety, the most powerful feature, is a good approach. Personally I tried explaining other smaller benefits first, e.g., immutable by default, move by default, no header files, but didn't work well as I thought. Exploring another language is a significant investment, and people need a significant reason (at least those that appear to be at first glance).

And there is a small marketing problem for Rust. The memory management is the big ticket thing we like to show off, but the big benefits of the language are much smaller and boil down to quality of life and composability.
Yes, banging on about memory safety sells Rust short, and drives away exactly the people who would benefit most from improved memory safety.

The language is just overwhelmingly better to code in than C, or Java, or C#, or Go. If the compiler were to be made fast -- and there is nothing like a fast compiler coded in your language to advertise its speed (and the reverse!) -- or anyway JITted, with a REPL, it could replace a great deal of scripting.

The comparison to C++ is much less compelling. Rust fans like to lump C and C++ together, but in modern C++ there are few temptations to memory unsafety. (They might be misled by crufty Mozilla code.) Meanwhile, the greater expressivity of C++ enables more powerful libraries, and each use of a good library eliminates many more than just memory bugs.

I agree with you, for sure. We had a huge community discussion about this in 2016: https://brson.github.io/fireflowers/
Rust has a great type system that enables the kinds of things you're talking about. It's like c++ and haskell came together and had a baby.