Should "cargo new" default to applications?

Currently, if you type “cargo new foo”, it will create a new project template in the ./foo directory. This template, by default, is a library template. When I first saw this, it struck me as a quirky default but didn’t pay all that much mind.

Fast-forward, and we’re teaching new users over and over via the book and materials to always pass --bin when they start learning cargo. I got to wondering if we possibly should change the default. How often are people creating a binary vs creating a library? Shouldn’t the default be the common case?

I did a quick browse at the survey data also to see, and ~550 of the roughly 2000 active Rust developers are contributing to crates.io. This seems to be one data point in favor of changing the default.

Sounded like a good question for a Rust internals thread. How often do you cargo new/init a new application vs a new library? Should we change the default?

9 Likes

A common[1] pattern is to create a library crate, but give it a main.rs which will use the library to do stuff (things like command line processing go into main.rs, and the core functionality is put into lib.rs). I personally like this approach because if I ever want to use the functionality I just wrote in another project, it’s already written as a library.

[1] Citation Needed. I don’t actually know how common this is, but at least anecdotally it seems to be a recommended practice.

5 Likes

I’ve added a “Create new Cargo project” feature to IntelliJ Rust, and it uses --bin flag (not customizable at the moment ;( )

I am usually creating a lib, but I think its more important what very new users are most likely to create. We could also turn these from flags to just another set of subcommands and make them mandatory, as in cargo new lib and cargo new app.

This could open cargo up to have user defined crate templates for initializing projects with certain dependencies, module structure, boilerplate, etc.

3 Likes

In my experience, I’m usually after --bin if I’m starting a project to do something. Furthermore, when I want a go about building a library, I am already thinking about the library and its structure, so the mental overhead of cargo new --lib seems smaller.

edit: I think user-defined templates sounds awesome! cargo new webapp, cargo new asmapp, cargo new macrolib, cargo new dbwebapp, the list goes on!

2 Likes

I had another thought – should we do a better job documenting the difference between a bin and a lib? Or documenting how to switch between the two (or how to add a lib.rs to a binary crate, or how to add a binary to a library crate).

I’m wondering if very new users are getting hung up trying to make a choice that, in the end, is not very consequential.

2 Likes

Going all meta: build opt-in telemetry for cargo, so we can make data-driven decisions on this stuff.

8 Likes

Yes please.

Telemetry is definitely interesting, but it feels like a whole conversation in itself. I’m afraid if we say “let’s wait for telemetry”, which may not come any time soon, we’re giving months/years to the current default and building up people’s muscle memory for it.

Right now cargo is not yet 1.0, and after it reaches 1.0 we shouldn’t be changing defaults (or perhaps only rarely at semver boundaries). Now is the time to make the adjustments when we can.

Its actually unclear to me what cargo’s semver story is right now. For example, a change that could cause cargo build to start failing for any crate is likely unacceptable. That’s a whole other conversation, and I think this change is fine, but I’m just saying its not 100% certain we can make this change.

Why not forcing the user to make a decision?

cargo new bin foo
cargo new lib foo
3 Likes

@dan_t - I saw @withoutboats mention a similar idea. We can do that, but it has the same breakage as changing the default, as “cargo new foo” would no longer work (assuming I understand you correctly).

I personally kinda like that “cargo new something” isn’t all that much to type, so I’m kinda leaning towards keeping it around if we can.

In case anyone is curious, the current version of the patch introduces a new --lib and also prints out a status when it’s done so you can see what kind of project you created. I’m hoping that even if we don’t end up changing the default, this will help users discover the other project type(s).

@withoutboats - agreed that different subcommands of cargo feel change-able but others don’t. This one is kinda borderline for me since it’s unlikely to be part of someone’s build script. That said, I didn’t want to change it without first reaching out to see what other Rust folks thought.

1 Like

In case anyone is curious, the current version of the patch introduces a new --lib and also prints out a status when it's done so you can see what kind of project you created. I'm hoping that even if we don't end up changing the default, this will help users discover the other project type(s).

If we aren't going to change the default, it would be incredibly helpful to introduce a command to quickly swap the setup. Maybe something like cargo add lib/cargo add bin to automatically patch up a miscreated project.

1 Like

Looking at the PR, I am really surprised there wasn’t already a --lib flag! It definitely seems like it should be possible to be explicit about that.

I’m really interested in the idea of crate templates, I’ll keep thinking about that space and try to come up with a more detailed proposal.

Default to bin and --lib flag seems more logical to me (because I always make the mistake of creating a lib when I intend to create a bin…)

My perspective is that (successful) programming is about building libraries and then combining them with a small amount of ‘glue’ code to turn them into a binary. So, in that sense, lib is the right default. Though, this doesn’t suggest that there won’t be more invocations of cargo new using --bin, however. I suppose it’s a very nuanced choice and I don’t see a compelling argument for changing it.

Not everything should be reconsidered over and over, forever. At some point just going forward with what you have is best.

I think --bin makes sense as the default purely for the newbie experience of playing with Rust, even if --lib is more common (which I think we don’t have any data about).

6 Likes

Sounds like a good use of that GitHub on BigQuery data.

I agree. In the lifetime of a Rust programmer, creating a new crate is a rare occurrence, and so it is not very important to optimize for an average Rust user’s experience. In contrast, a user who has less than 30 minutes of experience with Rust is very likely to a) create a new crate, b) want to run that crate (to see ‘hello world’ or whatever else). It makes a lot of sense to optimize for the early user’s experience here, since having to fix their mistake of not passing --bin would be a frustrating and maybe confusing distraction.

8 Likes