This is my re­sponse to the call for blog posts on what Rust de­vel­op­ment fo­cus ought to be dur­ing 2020. Much un­like my ex­tremely late post for 2019, which fo­cused en­tirely on com­piler im­ple­ment­a­tion de­tails, the fo­cus is on things that af­fect the end user ex­per­i­ence, spe­cific­ally the ex­per­i­ence past the ini­tial rose-­col­oured glasses phase of ad­op­tion.

Fig­ure out paths to­wards sta­bil­isa­tion of fea­tures

I main­tain a couple of Rust lib­rar­ies. Two of them, lib­load­ing and psm, share a pe­cu­li­ar­ity: both sac­ri­fice API safety in re­turn for abil­ity to com­pile on stable ver­sions of Rust. The two fea­tures in par­tic­u­lar are never_type and unboxed_closures. To give an ex­ample of where such a sac­ri­fice has been made, I’ll re­pro­duce this snip­pet from psm:

With un­stable never_type com­piler pre­vents me from spe­cify­ing F: FnOnce() -> ! as the bound. There is no choice but to doc­u­ment this in­vari­ant as free-­form text in­stead, which is not an ideal way to en­force such a crit­ical safety in­vari­ant.

Luck­ily, never_type is on its way to be sta­bil­ised and, pre­sum­ing no com­plic­a­tions, should be avail­able in stable com­pilers early 2020. unboxed_closures, on the other hand, are in a long-last­ing limbo and might re­main un­stable for the fore­see­able fu­ture.

I would like us to ded­ic­ate some of the time dur­ing 2020 to go through all fea­tures shar­ing unboxed_closures’ un­for­tu­nate state of mat­ters and eval­u­ate the im­pact these fea­tures have on the eco­sys­tem, fig­ure out what a path to­wards sta­bil­isa­tion might be, etc.

We want a fea­ture-­com­plete type sys­tem

Both never_type and unboxed_closures are, ul­ti­mately, fea­tures that make our type sys­tem bet­ter, more ex­press­ive and more com­plete. Just a “more com­plete” does not cut it any­more, we want a com­plete type sys­tem! To that end, there are at least a couple im­prove­ments to be made and fea­tures to be im­ple­men­ted. On top of every­one’s list there are these in­ev­it­able items:

  • Gen­eric as­so­ci­ated types;
  • Lazy nor­mal­iz­a­tion;
  • Con­stant gen­er­ics;
  • and many more…

I am well aware of the on-go­ing (ground-)­work ne­ces­sary to im­ple­ment most of these (see e.g. chalk). However, see­ing how im­pact­ful the lack of these fea­tures can be to Rust code tar­get­ing stable, I’d like there to be more fo­cus and clar­ity on pro­gress of these fea­tures.

Lets work on Car­go…

Speak­ing of “fea­ture-­com­plete”, Car­go’s lack of sup­port and pol­ish for many tasks off the beaten path comes to mind.

Cargo is the stand­ard build sys­tem for Rust code, and by its nature Cargo will define what build-­time pat­terns are used by Rust code in the broader eco­sys­tem. For ex­ample, many crates use build.rs as their tool of choice to link to ex­ternal lib­rar­ies, some­times it is used to gen­er­ate code, etc. Alas, build.rs is also of­ten at­trib­uted for ma­jor dif­fi­culties in­teg­rat­ing Rust code into al­tern­at­ive build sys­tems with re­pro­du­cib­il­ity as their core value. There are a couple of things we should ad­dress with build.rs spe­cific­ally: in­tro­duce sand­box­ing and per­haps make it not Tur­ing-­com­plete; in­tro­duce a way to list in­put de­pend­en­cies and for­bid ac­cess to other re­sources; per­haps in­tro­duce cap­ab­il­ity-­based se­cur­ity mod­el.

There are a fair amount of pa­per­cut is­sues that in­volve fea­tures and weird hand­ling around de­pend­en­cies, dev-de­pend­en­cies and build-de­pend­en­cies. In­ab­il­ity to use fea­tures with dev-de­pend­en­cies and cargo in­ad­vert­ently con­flat­ing fea­tures for dif­fer­ent kinds of de­pend­en­cies (1, 2) are easy to ac­ci­dent­ally stumble upon. Cargo is the fron­tend to the Rust com­piler. Leav­ing a bad im­pres­sion here will af­fect Rust as a whole. These pa­per­cuts must get no less at­ten­tion than we give to lan­guage ones (e.g. bor­row check­ing).

Less uni­ver­sally rel­ev­ant… with em­bed­ded use-cases and new tar­gets like wasm and RISC-V gain­ing in pop­ular­ity, Cargo needs to im­prove and ex­tend its sup­port for cross-­com­pil­ing Rust code. Ob­tain­ing and cus­tom­iz­ing tar­get sys­roots and us­ing them come to mind as a ma­jor pain point here.

…and im­prove de­bug­ging/in­stru­ment­a­tion

There is more to soft­ware de­vel­op­ment than ed­it-­com­pile-run cycle. This be­ing Rust, we do deal with a lower bug dens­ity, but they still ex­ist and need to be dealt with.

The first tool de­velopers are likely to reach for is a de­bug­ger. While our de­bug­ger sup­port is not bad per se, it is­n’t stel­lar either. It is pos­sible to print out a sens­ible stack trace and look at a vari­able. You might even be able to call a func­tion, much like when de­bug­ging C! As long as it is not a meth­od, that is. Or a gen­eric func­tion. Print­ing out an ele­ment in a vec­tor or a slice is also a non-trivial task.

I sus­pect that a full-fea­tured ex­pres­sion ex­e­cu­tion in a de­bug­ger is a hard prob­lem to solve and will take us more than a single year of fo­cused ef­fort, but we already have some found­a­tions with e.g. miri.

First class sup­port for bin­ary in­stru­ment­a­tion is an easier prob­lem to tackle. Fuzzers, san­it­izers and sim­ilar in­vas­ive tools are all ex­amples of bin­ary in­stru­ment­a­tion and they have been in act­ive use for long enough to demon­strate their be­ne­fits. Both within and out­side of the Rust eco­sys­tem. We should make these a first class fea­ture.

Smooth and shiny!

Work done through­out this dec­ade has res­ul­ted in an ex­tremely nice and well thought out lan­guage. Now, that the ad­op­tion rate is soar­ing, we need to en­sure that the first im­pres­sions, a ma­jor driver of Rust ad­op­tion, last through­out the less typ­ical tasks as well.