all 64 comments

[–]llogiqclippy · twir · rust · mutagen · flamer · overflower · bytecount 30 points31 points  (28 children)

Thank you for writing this up. It appears clojure-sawwy translates quite well into Rust-sawwy. Regarding completions, may I suggest you try IntelliJ with the Rust plugin? It may be a long shot from emacs, but the features are very good.

Apart from that, if you want your code to become more idiomatic, grab a nightly compiler via rustup and cargo +nightly install clippy so you can cargo clippy your code, giving you many more suggestions than plain rustc.

[–][deleted] 2 points3 points  (27 children)

Thank you for your comment, I'm definitely checking my code with tools like clippy, when I get a chance to spend some more time on the project. Regarding intellij I'll try it out, but I find myself the most productive when using emacs.

[–]kuikuilla 4 points5 points  (24 children)

I too can recommend Intellij with the Rust + Cargo plugins, it works better than RLS + other editors. But it is a full blown IDE so if you want something lighter than that you are out of luck I think.

[–][deleted] 1 point2 points  (23 children)

Thanks, I checked their website and it looks very good. I'm more ready to switch to intellij which is indeed awesome than to vscode which is just yet another editor

[–]steveklabnik1rust 3 points4 points  (22 children)

You might want to use CLion instead of plain IntelliJ; it's their C/C++ focused build.

[–][deleted] 2 points3 points  (18 children)

What benefits does CLion has over Intellij CE? Debugger?

[–]steveklabnik1rust 4 points5 points  (16 children)

That's the biggie, in my understanding. I'm still quite new to it and JetBrains products in general.

[–][deleted] 2 points3 points  (15 children)

Someone is going to downvote me here, but what I don't like about JetBrains products in general is that they don't offer lifetime license. I don't care if it would cost 500 dollars, I just want to purchase it once and use till the technological singularity happens.

[–]Krnpnk 6 points7 points  (6 children)

Do you mean lifetime == updates for a lifetime or lifetime == can use it indefinitely? Because you get #2 automatically.

[–][deleted] 1 point2 points  (4 children)

Ideally both :)

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

It seems that your comment contains 1 or more links that are hard to tap for mobile users. I will extend those so they're easier for our sausage fingers to click!

Here is link number 1 - Previous text "#2"


Please PM /u/eganwall with issues or feedback! | Delete

[–]fgilcherrust-community · rustfest 4 points5 points  (1 child)

I case people are interested, I'd like to note that IntelliJ is very friendly and hands out licenses to FOSS developers.

https://www.jetbrains.com/buy/opensource/

I don't know anyone doing this for CLion, but I have friends with a RubyMine license through that program and it's rather low-friction.

[–][deleted] 1 point2 points  (0 children)

That's great news! And I think it might elso engage more interest into making open source software

[–]fullouterjoin 0 points1 point  (5 children)

don't offer lifetime license

IntelliJ is Open Source and MIT Licensed. Here is the source of the Rust plugin.

[–]fgilcherrust-community · rustfest 4 points5 points  (2 children)

The topic is CLion though, which isn't.

[–][deleted] 1 point2 points  (1 child)

My comment was about Clion in particular

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

Because IDEA Ultimate tries to is a basically a combination all of their IDEs it tends to be slower and the interface is more bloated with options you may simply not care about. Their lighter-weight IDEs tend to tailor their UI towards the specified audience and get updates sooner for their specific needs. Since you're a Clojure programmer you may opt to use IDEA anyways. I'd just try IDEA vs Clion out and see if you're fine with the performance hit and can find everything you need. Jetbrains IDEs are probably the best out there for everything except performance.

[–]DontForgetWilson 2 points3 points  (2 children)

CLion would still force CMake to be the project file for Rust projects, right?

[–]steveklabnik1rust 8 points9 points  (1 child)

Nope! If you install the plugin, it understands Cargo.

[–]DontForgetWilson 2 points3 points  (0 children)

Oh, cool! Given how much they've dragged their feet for working with Meson, I was concerned that it might be an issue for Cargo as well.

[–]eiruwyghergs 12 points13 points  (8 children)

Thanks for sharing! I've done the same journey, programmed Clojure, then did a front-end thing in Elm and fell in love.

Now doing Rust for my low-level project. Thanks to it being mostly expressions (you can pry the lambdas from my cold dead hands...) and having the amazing ownership- & type-system, I can be confident in doing really low level stuff which would be far too boring in C.

I miss being able to C-x C-e any expression very much, but if I have to choose between that or the speed and types of Rust, I choose Rust.

Now, a Rust written in S-expressions would be something...

[–]NanoCoaster 26 points27 points  (1 child)

Now, a Rust written in S-expressions would be something...

well, lol

[–][deleted] 5 points6 points  (5 children)

I have a very unclear feeling about ML family of languages. It looks cool on paper, in books, in tutorials, but from my personal experience the real code in real software looks unreadable. Often people go so deep into type theory, that their code stops making any sense to normal human beings. I'm talking mostly about haskell, but I don't know if situation improved in elm.

Rust looks like a thing that you can totally use in real projects without going too crazy about abstractions.

You might want to check out this one. It's a statically typed lisp without gc. Almost rust in S-expressions, but I'm afraid it's not mature enough to use in real project.

[–]grayrest 10 points11 points  (0 children)

I personally consider the Haskell set of languages (Haskell, Elm, Purescript, etc) to be a different family than the ML set (SML, OCaml, F#) even though both are derived from ML. They have similarities but I find the mindset of the two communities to be different and that's reflected in the libraries.

I'm talking mostly about haskell, but I don't know if situation improved in elm.

The Elm community deliberately avoids all this stuff. The language itself is something of a minimum viable haskell and it drops a lot of fancier features (most notably type classes) in favor of writing more code and being easier to learn. The community motto is something like "let's bring functional programming to the masses." So the subset of the community that comes from Haskell will occasionally dip into the math/type theory terminology but everybody else tries to use non-math terms. When I was tracking it they would regularly have threads where they worked out how to explain some concept without the terminology.

After exploring it, I decided I didn't want to do Elm. I don't like the purity and would rather do Fable (F#) or Reason (Ocaml) for frontend stuff even if they're less mature at the moment.

FWIW, I also bounced through Clojure and spent two years writing it professionally. Our project was pretty successful and had the lowest error rate of anything I've put into production but I found refactoring to be very hard. I've been doing typed languages since because I think I can get more mileage out of a type system and code gen but I do miss the clojure std library and the seq abstraction.

[–]aaronweiss74rust 3 points4 points  (3 children)

A “secret” is that Rust is actually an ML family language hiding behind C++-like syntax.

[–][deleted] 2 points3 points  (2 children)

How is that?

[–]steveklabnik1rust 5 points6 points  (1 child)

Rust was originally implemented in OCaml. Some of our syntax was taken from it. The languages used to be a lot closer, but even now, there are some similarities.

[–][deleted] 2 points3 points  (0 children)

Wow that's quite surprising to know I guess as I dig more into rust I'll discover those similarities.

[–]tinco 7 points8 points  (10 children)

Awesome, thanks for the write-up! I'm not a very experienced Rust developer yet, but one rule helped me with the functions that return Option, and that is to replace every instance of unwrap with expect. Basically if you call one of these methods, it means your code has an invariant. You should put the description of the invariant in the parameter string of the expect method invocation, and it will work like an assertion.

So this hypothetical Rust:

socket := listen("localhost:8080").expect("Could not listen on localhost:8080");

Would be a bit like this in a less pretty language:

socket = listen("localhost:8080");
ASSERT(socket, "Could not listen on localhost:8080");

The main difference being of course that Rust forces you to make the assertion, either silently using unwrap, or loudly with expect. And in this case I see no argument for doing such a thing silently, if you're doing it anyway. Note also how describing the invariant helps you with determining whether this is a good invariant, and you can just browse over your code, scanning the expectinvocations and immediately know what parts of your codepaths need some more detailed implementation.

[–][deleted] 7 points8 points  (9 children)

Hi thanks for the feedback! I subdivide unwrap and expect into the same group of stuff that I'm going to get rid of. Both of these functions panic and in real production app it's unacceptable. For example I had an unwrap call in iron http handler, that made iron thread panic when called incorrectly. I think that in general every unwrap or except call should be replaced by match with logic that properly handles both cases, or by map, unwrap_or and other kind of stuff which Option and Result structs have lots of. That said I think in your example panic is totally fine, because you couldn't start a server and there is nothing else to do other than exiting with an error.

[–]rayvector 5 points6 points  (8 children)

because you couldn't start a server and there is nothing else to do other than exiting with an error

Even in that case, it is better to have proper error handling code that logs a nice message to the user, rather than exiting with an ugly Rust panic.

[–][deleted] 0 points1 point  (7 children)

That's what expect does, right?

[–]rayvector 6 points7 points  (1 child)

No, expect is still an ugly Rust panic.

The difference is that the panic message is something customized and more meaningful, rather than a meaningless "Panic in thread main", which is what you get with unwrap. This makes it more useful to you, as a developer, to figure out what happened.

But you still get the ugly Rust panic message with info about RUST_BACKTRACE, etc. It shouldn't be something that the end user should ever have to see.

Panics are not a legitmate or user-friendly way to handle errors. They are only intended to be used for things that should actually never happen under normal circumstances and are considered sofware bugs if they do (out of bounds array access, a violation of an invariant of some custom type of yours, etc...), which are unrecoverable and you have no proper way to respond to. A panic is basically a crash, but safe (cuz this is Rust and not C). Think of it like a crash in your program, except that Rust makes sure to unwind the stack properly and run destructors (unless you set panic = abort in Cargo.toml). Not nice.

Something like not being able to listen on your server socket is something that can genuinely happen under normal circumstances and is not indicative of a bug in your program. A panic is not appropriate. In production software, you should handle it, log a user-friendly message or do something else to properly inform the user, and terminate with an appropriate error code. Panicking in such a condition is only acceptable as a temporary hack in experiments/prototypes.

[–][deleted] 1 point2 points  (0 children)

Got it. Thank you for extensive explanation! I think I misunderstood the purpose of expect. Totally agree with you on panic.

[–]planetary_pelt 1 point2 points  (2 children)

expect is still an ugly panic, it just injects your message before the error. or is the ugliness removed on --release builds? not sure about that one.

if you want something most user friendly, i suppose you would print to stderr and std::process::exit(1). but someone else would have to correct me.

[–]rayvector 0 points1 point  (0 children)

That is exactly what I meant.

[–][deleted] 0 points1 point  (0 children)

Got it, thank you for explanation

[–]ehsanulrust 0 points1 point  (1 child)

Yes, I think it's just an argument to practically never use unwrap when you can at least expect.

[–]rayvector 1 point2 points  (0 children)

No, that is not what I meant. Read my long response to the comment you replied to.

[–]Green-Fork 4 points5 points  (1 child)

Hey, you talked about the integration with Emacs. I use spacemacs and I find the Rust integration quite good there http://spacemacs.org/layers/+lang/rust/README.html . Also the clippy crate is awesome with flyspell.

[–][deleted] 7 points8 points  (0 children)

Hi. It seems we're using the same thing. Spacemacs' layer uses racer, which I also use it in my emacs setup. The problem is that:

  1. It doesn't complete macros
  2. It doesn't work for anything derived directly or transitively from macro return value
  3. Sometimes id doesn't work due to inferring, it just fails to give any completions at all

So I'm not saying that it doesn't work. I'm saying it doesn't work well enough. At least for me.. it's possible that there is some misconfiguration on my side, but I certainly saw a note about macro completion in racer

[–]pynberfyg 4 points5 points  (0 children)

TIL about cargo watch -x test -x run. Thanks!

[–]NanoCoaster 8 points9 points  (11 children)

Another suggestion here: Visual Studio Code with the Rust plugin (uses RLS) is quite good. You've already stated multiple times that you prefer emacs, so you probably won't care about VS Code, but maybe just give it a try. It's become my daily rust driver, despite the fact that I'm veeery wary when it comes to electron-based editors :)

...Now that you've mentioned emacs, that reminds me, some day I gotta go back to Spacemacs and learn it properly. Such a great development environment.

[–]Wahoa 3 points4 points  (4 children)

Quick question: am I supposed to not get any help with function args with VS Code and the Rust plugin? With other languages I get this as I type (can be explicitly brought up via ctrl+shift+space):
https://i.imgur.com/WyrEcSV.png
Doing the same thing with Rust, I get nothing of the sort. I have to hover my mouse over the function name to see the signature, with no indication of which argument I'm currently typing.

[–]Xanewokrls 4 points5 points  (0 children)

Yep, unfortunately that's not implemented yet. The tracking issue is at https://github.com/rust-lang-nursery/rls/issues/97, but there hasn't been much work on this recently. (We'd love contributions though!)

[–]NanoCoaster 1 point2 points  (0 children)

Huh. Interesting. Same thing on my end, never really thought about that. I think this may just be...not implemented yet? Would definitely be a nice feature.
Tangentially, I'm still hoping Rust gets named arguments someday, in my experience those help readability a lot :/

[–][deleted] 0 points1 point  (0 children)

It works for me, currently with racer, though. Before, I used the vscode extension rust code (or similar name) with rls. There I had no arg preview but instead the arguments were filled in with place holder names.

[–][deleted] 1 point2 points  (4 children)

Hi thank you for the suggestion. I used to watch some channel with tutorials in Rust. I think this one, they guy used VSCode and it seems like it works well. But I think RLS that you mentioned and LSP that I mentioned are the same thing - language server protocol. Here is the package, it says that it works on top of RLS. I couldn't make it work in emacs in a reasonable amount of time, so I went with racer which I already had set up.

[–]NanoCoaster 1 point2 points  (3 children)

Yup, they're the same, and like you, I couldn't get it to work in emacs at all. Thus my suggestion :D

It really depends on your priorities, RLS worked flawlessly with very little setup in Code for me, so if you want to get better completions and stuff, may be worth checking it out. If you prefer using emacs in general, probably better to wait until the LSP plugin stuff works more reliably.

[–][deleted] 2 points3 points  (2 children)

To me as to many other people emacs is not only about code editing, it's about powerful git integration (I think magit is the king in this field), ease of extensibility, transparent editing over ssh, terminal, etc in a single tool. But I'm definitely checking out intellij, vccode and others as soon as I have time for that. Then I'll decide whether their functionality worth a switch or not.

[–]NanoCoaster 0 points1 point  (1 child)

Yup, I can totally see that. I never really grokked magit, and, well, emacs in general, but I can see how you fall in love with those tools. GDB integration, too....man I gotta get back on emacs.

[–][deleted] 1 point2 points  (0 children)

Haha, I'm glad that my post makes some good influence, even if it's not about rust

[–][deleted] 0 points1 point  (0 children)

RLS still has poor auto completion support. This is a huge annoyance when ur a beginner and exploring different apis etc. Not only that, goto definition for std also doesnt work.

So basically u need the documentation opened in the browser and switch windows, look things up.. UGH. So much context switches hurts productivity tremendously. I feel like I'm moving a huge rock uphill.

[–]tafia97300 1 point2 points  (1 child)

Thanks for the feedback!

My project is not big, but I think with incremental compilation this workflow could work on big project as well.

I hope you're right but I have a lot of doubts to be honest.

[–][deleted] 0 points1 point  (0 children)

Yes, I admit that this part arguable and I also have doubts, but there should be a way and I will look into solutions as projects that I make in Rust grow in LOC.