Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Try Out Rust IDE Support in Visual Studio Code (rust-lang.org)
265 points by Rusky on Aug 18, 2017 | hide | past | favorite | 82 comments


I have been using this for a few weeks, as a newcomer to Rust. Although it has some issues, I would not try to develop Rust code without it. It is incredibly useful and works well enough for day-to-day use.

Some of the issues I've found:

* Code completion sometimes simply fails to work. For example, inside future handlers (probably because this involves a lot of type inference).

* When errors are detected only the first line of the compiler error message is accessible in the UI, often omitting critical information and making it impossible to diagnose the problem.

* It is often necessary to manually restart RLS, for example when your cargo.toml changes. It can take a very long time to restart if things need to be recompiled and there isn't much in the way of progress indication.

* This is more of a missing feature, but type inference is a huge part of Rust, and it's often difficult to know what type the type inference engine has chosen for parts of your code. There's no way to find out using RLS in VSCode that I've seen, or go to the definition of inferred types, etc.

Other issues I've seen as a newcomer to Rust:

* It's very easy to get multiple versions of the same dependency in your project by accident (when your dependencies have dependencies), and there is no compiler warning when you mix up traits coming from different versions of a crate. You just get impossible-seeming errors.

* Compiler speed is a big problem.

* The derive syntax is super clunky for such an essential part of the language. I think Rust guides should emphasize derive more, as it's unclear at first how essential it really is. Almost all of my types derive multiple traits.

* In general, Rust is hard. It requires a lot more thinking than e.g. Python or even C. As a result, my forward progress is much slower. The problems I have while coding in Rust don't even exist in other languages. I'm sure this will improve over time but I'm not sure it will ever get to the point where I feel as productive as I do in other languages.


> The problems I have while coding in Rust don't even exist in other languages.

Yes, Rust probably requires more thinking to program in than C. But C's hard-to-troubleshoot runtime segfaults become hard compiler errors (with line numbers and useful error messages!) in Rust. Trust me, I've had plenty of fights with the borrow checker. But, once I finally get it to compile successfully, I know that my program isn't going to fail at runtime by accessing memory in some invalid/incorrect way.


This is true and I love this about Rust. However from a pragmatic point of view, I'm definitely spending a lot more time wrestling with the type system than I ever spent debugging memory errors in C. Overall I am less productive. As I said that may change, but I am not certain that it will.

To me the benefit of Rust's type strictness is not productivity, but security. I would not write any network-facing code in C today. I would choose Rust over C even with the productivity hit. But other languages, such as Go, might be a better choice if productivity is higher.


90% of Rust's draw to me is that the type system will give me a proper fight by default, instead of C++'s constant uphill battle of researching and opting into everything under the sun, filtering out the false positives, and then fixing the latent and not so latent problems uncovered by such efforts.

I haven't been nearly as lucky as you when it comes to avoiding memory errors (and debugging them). Large very active multi-team projects with years to decades of version history behind them results in a huge haystack. Individual memory or threading bugs can eat weeks or more, and with that many committers - I think there's some kind of quadratic or worse time sink in there. Memory safe languages fix some of that, and are massive productivity boosts as a result, by either preventing or making shallow such bugs.

To me it's not that Rust's borrow checker sounds like some good idea on paper, or just for security. To me, Rust's borrow checker is merely a unified, consistent, standard, and enabled by default implementation of much of what I'd been hacking together through the haphazard use of extensions, static analysis, runtime tools, and disabled by default annotations in C++ - since before I even knew what Rust was - with the specific aims of boosting my productivity and reducing my stress. The security is a nice bonus too.

I've "replaced" C++ with C# in a lot of cases. Rust is threatening to replace most of the remainder (except for existing projects which need to be maintained and don't make sense to rewrite.)


C# and Rust are a wicked combo. The fact that you can pass delegates as fn pointers down to Rust is freaking sweet from an FFI perspective.


Do you have any pointers to projects doing this?

I'm very interested in rust and a C# guy during the day. A decent, as in 'serious', example showing rust integration would be quite appreciated.


Nothing public unfortunately.

It's pretty straightforward though. Just declare a delegate with the same type signature as a your C function callback. Add that as the signature passed in to a native function and C# will make sure to marshal it to a standard C function pointer.

Only catch is if you want to keep a hold of the pointer in native you need to make sure to create a GCHandle to the passed in delegate with an identical lifetime. Otherwise the GC will collect the delegate from underneath you.


> ... a lot more time wrestling with the type system than I ever spent debugging memory errors in C

that's because for programs that you wrote in C, there exists hidden issues that you never paid a cost to fix (which, potentially saved you the effort if in practise it never was problematic). In rust (or haskell perhaps?), you pay that cost up front, and then the "time lost" to debugging/runtime issues had it been in C wouldn't show up as a "reward"!

I find this to be a troubling way to think about programmer productivity - a lot of opponents to functional programming or formal methods use this point against it. Spending this large an amount of time, solving issues that _may_ not be a real issue in production, just isn't worth the cost. I don't agree, but i suppose it's a judgement call for the programmer.


This is just anecdotal, but for me productivity in Rust is way higher than C++. Sum types and pattern matching, affine types, the choices made by the standard library, and Cargo all contribute to that.

I suspect once you get your head wrapped around Rust's type system idioms things will get better. I am interested to see how this turns out for people in general, though.


I cannot say the same due to lack of support for GUI toolkits, the way the borrow checker handles callbacks, or mixed debugging support.

You can get sum types in C++17 and with boost::variant in early versions.


That's fair, the ecosystem certainly isn't ready for every use case.

What specifically do you mean by "the way the borrow checker handles callbacks"?


It is described in the Non-lexical lifetimes RFC under "Closure desugaring".

https://github.com/nikomatsakis/nll-rfc/blob/master/0000-non...

Basically if you have a struct to represent, lets say a Window, and inside of it try to reference instance variables on a closure that would handle a button click for example, self will be moved.

There are a few workarounds, but all of them are less ergonomic than any mainstream GUI toolkit.


I'd say it worked similarly for me.

There was an initial hard slog around the borrow checker, but once it all clicked it's been very smooth sailing. The only thing I've had trouble with in the months since is when I went to write some macros, but that was more me not reading the docs closely enough. I'd say I am very productive in it now and I don't view any of Rust's features as being a productivity problem.

If you're struggling with Rust, I'd say keep going until you get that "click."


C++ is somewhat of a low bar, because of the state of the art in package management in C++ land is "download a header-only library". C++ does have sum types in the form of boost::variant, but boost is an abomination.

The danger to Rust is that for many projects it wins by default because the alternative languages are immature, rather than because its performance/security capabilities are actually worth the productivity trade-off compared to other languages.

Once Swift matures a bit, it will take a lot of the lustre from Rust.


Productivity is certainly very high in go compared to rust; however, I've found that confidence about how the code executes is much easier to acquire in rust if it compiles.

Regarding the type system, it's definitely a sharp learning curve; there are certain patterns that are trivial in C++ that I still don't quite understand how to best translate. I suspect non-lexically-bound lifetimes will help a lot here iff they are viable.

However, debugging is a complete breeze compared to C++ because of a) the borrow tracker and b) the errors are much more readable because of a general lack of template soup.


> I'm definitely spending a lot more time wrestling with the type system than I ever spent debugging memory errors in C.

There is no way you can reliably make this claim. It smacks of rosy retrospection bias.


Running `cargo tree -d` helps with checking if you have multiple versions of a dependency and where they come from.

You can install it with `cargo install cargo-tree`


> there is no compiler warning when you mix up traits coming from different versions of a crate. You just get impossible-seeming errors.

There is a check when error messages are generated to detect messages like "expected X, got X" and add a warning that you might be mixing different versions of the same crate.

There are probably some cases that slip through, but if you file an issue with your specific example or look into the compiler yourself, you might get it fixed (my one patch in rustc handles "a::b::X" being reexported and accessed as "a::X").


> I have been using this for a few weeks

> In general, Rust is hard

It's only in first weeks. Soon you will use borrow checker and lifetimes rules without any thinking, you will just do it automatically.


> This is more of a missing feature, but type inference is a huge part of Rust, and it's often difficult to know what type the type inference engine has chosen for parts of your code. There's no way to find out using RLS in VSCode that I've seen, or go to the definition of inferred types, etc.

VS Code has a 'code lens' feature that allows extensions to display annotations above each lines of code - you can see it in action if you install e.g. the Git Blame extension.

Some language plugins use that feature to display inferred types; the Rust plugin could do the same.


With TS/JS, it will show this when you hover the cursor over the variable (or invoke it with a keyboard shortcut)


the plugin seems to do it sometimes. definitely a useful feature when learning. can do codelens too so you don't have yo hover. would be a nice option.


Rust is not only a fantastic language, but the level of community involvement from the devs is just completely unlike any other language I've seen in a very long time. That really makes me excited that it will be adopted in the industry over time and ideally replace some of the nightmare-level C++ code out there.


I'm not that optimistic. In my experience, nightmare-level code will be written by the person who wrote it no matter what language they use. Rust doesn't look all that cleaner than C++, just that it has a few more safety guarantees. I'm sure terrible code will be written in it. And I'm sure clean code will be written in it that people without context will call terrible code.


The way I'd put it is, I'd be much more confident in the ability of an open source project to survive receiving contributions from the general public if it were written in Rust rather than C++.


Yes! This has been my view on Rust for a while -- it's a relatively inexpensive way to boost productivity and general security of projects. This is especially true when the alternative is formal verification, which is less ergonomic than Rust and effectively would require a rewrite of C code anyway.


I've written awful Rust code myself, and I'd still rather be writing Rust than C++, because sticking to Rust idioms makes it harder to do the wrong thing without it being obvious.


I think the bigger problem is that nightmare code is the stuff nobody understands. So it's the hardest to re-write, because nobody knows what it does.

So nightmare code is the code that lives forever, whereas well-written code is easily replaceable.


People can definitely write bad code in any language, however Rust relentlessly forces you towards single-ownership(unless you're using RefCell) which is a really good thing.


The thing is nightmare Rust code is usually obvious - the dev is using a lot of unsafe{} blocks, or Cell, or is spewing out a really complex type signature.

With C++, the nightmares are just really obscured pointer manipulation that can work but have infinite edge case failure states that cause endless undefined behavior.

In Rust, if it compiles, it is at least constrained to only break what the dev explicitly broke, it doesn't break everything.


Note that Cell is entirely safe and not problematic. It is RefCell that can cause problems.


People will write awful rust code. The impact of this will not be an attacker's ability to completely take over a system. That's a level of "awful" I'll take.


I haven't had the chance to try the Rust language mode, but I've been using VS Code for all my julia development lately, and I'm pretty impressed. It's quite a nice editor. I avoided using it for a very long time because I thought it'd match Atom's slowness due to their shared Electron heritage. But for some reason VS Code feels a lot snappier. Not quite Sublime levels, but perfectly usable.


[Hijacking to talk about VS Code in general]

Moved to VS Code last week. Coming from JetBrains products, the performance is wonderful. On the other hand the quality of language plugins varies quite a bit, though I've gotten the debuggers and jump to definition to work in PHP and Python. Oddly go to definition can be janky in Javascript [1].

There's also a very nice plugin called vscode-journal [2] that works great for quick logging tasks and notes.

Compared to the JetBrains products I am not a fan of the Git interface, but I think Atom shining in this respect could motivate VS Code to provide a more coherent SCM interface.

I am happy to be back to one-editor-to-rule-them-all. For years I used Emacs, but after using the JetBrains language specific IDEs with quality debuggers built in, I gravitated to them. VS Code seems to strike a fine middle ground.

[1] https://github.com/Microsoft/vscode/issues/19942 [2] https://github.com/pajoma/vscode-journal


Just curious, what are you system specs?

I like VS Code and I've been using it for Rust projects, but I have lots of intermittent UI jankiness, where I will start typing and nothing will happen for up to a second or two. In addition UI operations in general are perceptibly (though not to me annoyingly) slower than a native application. It's not all the fault of extensions: all I had installed was Hg and the Rust extensions, and though the latter, particularly with RLS mode enabled, did make things worse, the problem's still there without them.

To be fair, it's an older laptop (Core 2 Duo), but it has absolutely zero problem running Sublime or even full-on Visual Studio, and to me it's a little disappointing.


It looks like code completion is extremely basic. I tried this:

    struct Point { x: i32, y: i32 }

    fn main() {
        println!("Hello, world!");

        let pt = Point { x: 1, y: 2 };
        println!("{} {}", pt.x, pt.y);

        let v = vec![ pt ];
        let vpt = &v[0];
        println!("{} {}", vpt.x, vpt.y);
    }
And I can't get any dot-completions on vpt (but I can on pt). Which is also kinda weird, because if I hover over vpt, it does know that it is a &Point...

Even more weird is that if I add a type declaration to "let vpt" (specifying the same type that would be inferred), then completion works.

That sounds like a really basic scenario... I mean, type inference for locals is pervasive in Rust.


> I can't get any dot-completions on vpt > Even more weird is that if I add a type declaration to "let vpt" (specifying the same type that would be inferred), then completion works

I'm fairly certain the reason for this is that RLS (and every other Rust editor/tool I've tried) isn't able to handle completions for things coming from macros (transitively or otherwise). Although the prevalence of the `vec!` macro might make it seem like the completion is "extremely basic", variables coming from macros are pretty much the only case I've found that RLS can't completely properly for. If you manually write the code that the macro would produce (i.e. `{ let mut temp = Vec::new(); temp.push(pt); temp }`, I think it should work fine.


It might also help to manually annotate the type of the binding being assigned to.

            let v: Vec<i32> = vec![ pt ];
            let vpt = &v[0];


Nope, doesn't help (corrected to Vec<Point>). The only thing that works is annotating the vpt binding itself.

In any case, if you have to annotate all local bindings for completion to work, that's not idiomatic Rust anymore.

Another interesting thing that I've noticed, is that it does know what vpt.x and vpt.y are - when hovering over them, it correctly says that they're i32. So the type inference works as it should. It's specifically completion that is broken here for some unclear reason.


I wonder if this is an issue with the VSCode extension rather than the RLS then; all RLS can do is provide information to the extension, so maybe the extension just isn't using the information.


It's not an issue with vec! - the same problem occurs if I use Vector::new and push. It seems to be a problem with the vector itself, or perhaps indexing.

Besides, it does know the type of vpt in code snippet above - like I said, when I hover about it, it correctly tells me that it's &Point. So it clearly can handle macros, or at least vec! specifically.


I suspect this is an issue with Racer, the tool that provides the completion information.



LOL. I mean, it sucks to be that guy, but you have to consider that a project editor has the possibility to overwrite your files with gibberish at any time. I would never load some new software that was supposed to manage a project on my project of 5000 files without having a real good backup first. The same way if I was a video editor and was switching to new video editing software, I would make sure to have a good copy of the originals as well as the work up to that point saved so that I could recover any unexpected weirdness of the new software.

None of that helps this guy. I understand that. Maybe Visual Studio Code could have worded it better. This guy played fast and loose with the safety and integrity of his work and he was bit by it. I do feel for him, but more in the way I feel for anyone that does a stupid thing they should have thought more about first, but this is more a problem of him not understanding what he was doing and the category of software he was giving control of all of his files to. If you plugged your weirdly formatted USB drive (but usable by your other systems) into a computer and it said "We can't read this! Should we reformat?" you probably shouldn't click yes if you don't have backups of what was on that USB drive.


> but you have to consider that a project editor has the possibility to overwrite your files with gibberish at any time

You really need to use other editors if you think so. Removing 15k files without any warning is a pretty lame move from editor developers.



This doesn't tell me what changes it's going to discard. The word "uncommitted" should probably be in there somewhere, and I would use "delete" instead of "discard" for a file operation. As in "Delete all uncommitted files and file contents and set them to the last git commit?". Plus a list of changes that will be made, like:

- delete a.txt

- delete b.txt

- delete 123 changed lines from c.txt

As it's worded it's quite vague what's going to be discarded from where and how. Presumably if you know which button you clicked, it's more clear, but if you mis-click and don't know what you clicked, you can quite easily make the same mistake.

Finally, he's right that programs shouldn't be deleting files without a way to recover them in 2017. That operation should require the same level of directed intentionality as launching a nuclear missile.


This reminds me of when I was 12 years old, learning to program in BASIC, and my probably 15th program was drawing a star on the screen in ASCII.

I named it *.bas, which the interpreter actually ran despite that being a terrible name for anything.

Yeah, I lost all of the other programs in the directory.

Use backups and source control. Sometimes you need to learn things the hard way, but this one, take it from us. :)


Honestly if you have three months of work not in version control and not backed up and you're willing to click a button labeled "discard" anywhere near your files without taking any precautions then you have only yourself to blame.

Also, I feel bad saying it, but I haven't laughed this hard in a while.


That does sound like a bad UI though. Perhaps vscode could stage the files before, so that they end up in Git's objects at least? Or somehow store them in the reflog


If I'm reading the situation correctly, Git was also involved in the problem.

This person seemed to have his project under Git version control... but he hadn't committed for 3 months, which implies he viewed Git as an inconvenience at best. Perhaps the company is just passing around some project scaffolding?

Any other GUI over your version control software is going to have the option to discard recent changes. Discarding changes sounds like a potentially damaging thing, so it makes sense that you'd want to gate it with a warning dialogue. But they did gate it, and if files are deleted in the process, they do say DELETED in caps, and then they gate you again with another popup by saying IRREVERSIBLE in caps.

Adding a third popup gate would be excessive.


> but he hadn't committed for 3 months

I get nervous when I haven't commited for 2-3 days. Since I don't want to commit broken code, I make a patch and send it somewhere for peace of mind. In addition to that I have an editor add-on that saves a copy every single time I save a file. One time it allowed me to recover the work of several days.

You don't need backups until you do. Some people learn the hard way.


> I get nervous when I haven't commited for 2-3 days.

I get nervous when I haven't commited for 2-3 hours. I can't even begin to comprehend how someone could make 5000+ file changes to a git repo for 2-3 months and not commit once. He probably didn't know about version control, and was working on someone else's project?


My changes tend to be small, slow but profound. I think a lot on most problems I solve. In other areas of development it would probably be 6-8 hours. I get nervous because the hard disk can break at any moment, but it's unlikely enough that repeating 6-8 hours worth of work every 2-3 years is an acceptable risk to me.


Git stash is a great tool to keep unfinished work, IMO. You _stash_ your changes if you need to work on something else, and then you pop it from the stash to continue working on it. No commits, no branches. Just stash and pop.


I use stash all the time. That's not the problem. The worry is losing the whole repo because of hard disk failure.


I use an AWS instance for development (on Windows, I suppose that Linux could also have a similar setup).

This setup allows me to use AWS snapshots to have the disk backed up (crash consistently) once a day (but it could be once an hour or even less). I shut down the AWS instance when I do not use it because it starts up again in seconds when I need it.

When I do not have a fiber connection at hand, I can use my 4G phone as a personal hotspot with 60-80ms latency to AWS Ireland from my country, which gives a great experience with RDP, has been a game changer when in the move.

Since RDP traffic is about only 10MB/hour, even if you work 160 hours a month using the 4G phone you are at 1.6GB/month, which costs about EUR 7/month.

I happen to use various Macs as client machines, but their role is mostly a thin client with occasional web browsing.

This VDI approach allows the Mac specs to be quite low (one of my Macs was bought in 2009). In any case, if I ever need to upgrade because of software becaming heavier, I just need to change the AWS instance type.


> I have an editor add-on that saves a copy every single time I save a file

This sounds very useful! Is this addon for vscode? Please educate me :-)


It's an atom addon called local-history. It seems there's a VS code addon of the same name with the same functionality.


This sounds very wasteful unless it is doing diffs in the background. In which case, git would be better.


It doesn't do diffs and it's no replacement for git, but complements it as one added layer of protection. It's kind of wasteful but my local-history is 100 mb big after some months. And you can tell it to auto purge anything older than X days. I would put 90 days as default instead of 30.


It's pretty bad UI design, but pressing the discard button does open a confirmation box that says "Are you sure you want to discard ALL changes? This is IRREVERSIBLE!"

With that kind of a message, it's amazing how he didn't think twice about discarding them. Especially when he didn't have a proper source control before.


3 months of code work and no version control...

You have to wonder if he actually learnt a valuable lesson or just ran away blaming Microsoft...


I'm not hopeful:

> I don't need to explain why I don't have a private repo with my stuff. It is the software's concern NOT to destroy the integrity of a computer like a damn virus. You come here, see my despair and berate me for something that was not my fault, and has happened to a lot of other people? Fuck you.


While I think he should have learn his lesson before, also I think it should show the list of files it would delete.


He most likely didn't have a proper source control because he didn't even know what it is. For someone like him your proposed warning wouldn't be effective, because according to his belief he didn't change anything yet.


I tried it, it works really nice. If you are looking for an alternative, the Intellij IDEA works very well when you install Rust plugin.


I've recently switched to using Intellij for my Rust coding, and it's been phenomenal. I'm not usually much of an IDE person, but the experience has sold me enough on Jetbrains IDEs that I picked Gogland for my editor for the Go code I'm starting to do at work now, and I've been very pleased with it.


The vscode rust support is progressing nicely and if vscode is already your go-to editor it's the obvious choice.

However if you just want to dip your toes and get going with rust with minimal fuss, I find IntelliJ community+Rust to be the best combo. Vscode+Rust is not as polished yet.


Does this support macro expansion of any kind? I'm currently using the plugin for IntelliJ IDEA, and it works really well aside from completely lacking support for macros, which makes its type annotations and similar features nearly useless for the project I'm working on.


It does support macro expansion for some things. i.e. all of the type information is gathered post macro expansion.


At least the last time I tried it, RLS wasn't able to handle inference for values coming from macros (e.g. completing methods on a variable initialized with `vec![...]`. None of the Rust tooling/editors I've tried thus far have been able to handle that, so I'm hoping that either RLS or Intellij's Rust plugin add it soon.


I'm not sure when you last tried, but IntelliJ Rust handles completing methods on a variable initialized with vec![] for me just fine.


Anyone here writing Rust on Windows and using WSL (Windows Subsystem for Linux) in your workflow?

I've found using WSL's "bash -c" from my Rust project's working directory in Windows to be a rather elegant way to compile and run code for a Linux target.

Theoretically it should be possible to remote debug Linux binaries in WSL from an editor in Windows, but I haven't had time to explore this yet. Both GDB and LLDB have remote debugging functionality.



Autofix doesn't seem to trigger for me, would someone confirm it's not just me?

try this in your editor

    let x = 4;
    if x = 5 {}
it should figure out you wanted x == 5.


This should work (it's my goto test case). You have to put the cursor in the erroring code to see the possible fix icon in the margin. If you don't see it please file an issue with the project you're trying this in and I'll investigate.


my bad, in a new project it works just fine. I'll keep investigating.


I would love Rust support in Visual Studio proper...


There is syntax highlighting, but that's it so far.


Is anyone working on support in Atom?


From looking at the README in Atom's languageclient (the editor side of the language server protocol), it doesn't look like there's a dedicated Rust plugin yet[1], although I'd like to think that there would be some way to use it without needing a dedicated plugin given that it's the whole point of the language server protocol.

[1]: https://github.com/atom/atom-languageclient#available-packag...




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

Search: