rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
98.34k stars 12.72k forks source link

Tracking issue for libcore + no_std stabilization #27701

Closed alexcrichton closed 8 years ago

alexcrichton commented 9 years ago

This issue is intended to represent the outstanding issues for stabilizing libcore and allowing its usage on stable Rust. There are a number of features currently associated with libcore:

(note that core_float will be handled in a separate issue)

The design of libcore largely mirrors that of the standard library (good) but there are a few deviations:

Overall there are a number of tasks that probably need to be done before stabilizing these items:

bstrie commented 9 years ago

Given the amount of uncertainty raised in these comments over the current design, I'd like to see a concerted outreach effort to users of std-less Rust to give their feedback. I'll start reaching out tomorrow to Redox and #rust-osdev, but if you can think of others please don't hesitate to point them here.

alexcrichton commented 9 years ago

My opinion on this is that while the FCP was a good time to think about alternatives to make sure we're confident in the current design, none of the proposed alternatives have been "clearly better" than today's situation. I don't think that discussion about the design equates to uncertainty, and this discussion has not been a unified "everything is not so great today" front.

briansmith commented 9 years ago

Alex, is it your opinion that all the negative feedback in this discussion should be left unaddressed by leaving the design unchanged? Are people really satisfied with not addressing the issues mentioned in https://github.com/rust-lang/rust/issues/27701#issuecomment-143313535?

If so, could you at least clearly explain how one can write a library that works equally well on [no_std] mode and non-[no_std] mode, and how the design will allow us to change libraries that don't support explicitly support [no_std] so that they do, without breaking their source code backward compatibility?

(Still, I do think the existence of "cargo features" suggests that people in the ecosystem at large don't want to just break things up into lots of microcrates (or can't do so). After all, why aren't they using facades instead of cargo features? Similarly, platform-specific functionality seems to fit into more cleanly into the model I'm talking about.)

Exactly.

nikomatsakis commented 9 years ago

I do think that this issue is important enough that I'd like to make sure that the @rust-lang/lang team has an opportunity to discuss it in detail, as well as the core team.

nrc commented 9 years ago

+1 in favour of possible redesign - it sounds like some variation of the subset design is possible and preferable. I think we should not stabilise for now and cast back to the RFC process to nail down (or at least further investigate ) a design.

alexcrichton commented 9 years ago

The libs team discussed this during triage today, and the decision was to re-up this for FCP in the next cycle. The conclusion reached, however, was that it is unlikely to move forward with a different design than today's. The were a few points of rationale for this:

In going through another FCP, however, we'd like to have some more discussion, but focused around either:

We'll be chatting with the lang/core teams (as @nikomatsakis mentioned) over the next few days, and I'll likely post updates after that as well.


@briansmith

I personally think it's a bit of a mischaracterization to say that all the feedback here has been left unaddressed. I've tried to always respond to questions and concerns in my comments here, and if I've left anything out it's been purely by mistake!

I tried to answer your question above, but I can try to go into more detail here as well. A no_std library doesn't really have a reason to ever not have the no_std attribute, so in that sense a "non-no_std mode" doesn't necessarily exist. If a crate wishes to export functionality that does require std (but conditionally export it) then it can simply conditionally link to std.

Can you elaborate on what you mean by "source code backward compatibility"? I'm not entirely sure what constraints this implies.

Currently, however it hasn't in the past been a design constraint that adding no_std support should be possible with 0 source code modifications, so having a crate start supporting no_std will generally mean:

  1. An attribute is added to the crate.
  2. Imports are renamed to core instead of std, but this can also be dealt with via extern crate core as std in the crate root.
  3. If necessary, functionality requiring std is put behind #[cfg] directives, likely exposed via Cargo features.

You can see an example of this in action where the mod std in this case wasn't necessary, but highlights how a no_std crate is written to center around core rather than std in terms of imports. The crate, however, compiles on today's stable release (using std), and it all interoperates together.

nikomatsakis commented 9 years ago

We had some discussion in the @rust-lang/lang meeting. I think there was general feeling that indeed the "subset" idea has some promise, but the current crate facade also has many nice properties, and we have a lot of experience with it. @huonw was a bit concerned that the subset idea did not play nicely with the allocator crate design, and while I think it can be made to work, I have to admit I'm not entirely sure. Therefore, we'd be ok with stabilizing the facade.

nikomatsakis commented 9 years ago

While we're discussing, can I throw in a small bikeshed? I've never been crazy about the #![no_std] attribute's name. I feel like I'd prefer an attribute like #[core] or #[use_core] -- that is, one that declares that it only uses core, not that it doesn't use std. After all, #![no_std] is a bit misleading if there is some other module that has an extern crate std.

alexcrichton commented 9 years ago

I wouldn't feel too bad renaming to #![core] either, although I also wouldn't shed too many tears to stick with #![no_std]

ahmedcharles commented 9 years ago

Is it possible to do the following? (I'm asking because I'm not quite sure how to check.)

#![no_std]
extern crate core as std;

mod mod_using_core { ... }

mod mod_using_std {
    extern crate std; // I'm not sure if you can put extern crate here, but the idea being that only this uses std.
    ...
}

Basically, can I use std to refer to both core and std.

alexcrichton commented 9 years ago

@ahmedcharles yes, that indeed works!

ahmedcharles commented 9 years ago

Thanks @alexcrichton.

My next question is... let's suppose that there's an alloc crate that can be used with core by adding #![alloc]. Can I then write this?

#![no_std]
#![alloc]
#![feature(no_std, core)]

extern crate core as std;

mod mod_using_core { 
    use std::mem;
}

mod mod_using_core_and_alloc {
    extern crate alloc as std;
    use std::mem; // Does this refer to alloc or core?
    use std::allocate; // arbitrary symbol that requires allocation support.
}

mod mod_using_std {
    extern crate std; 
    use self::std::string::String;
}

fn main() {}
alexcrichton commented 9 years ago

It doesn't quite work that I don't believe. Most of this is pretty orthogonal to #![no_std], however, as it's just dealing with basic name resolution in Rust. Here's what'll happen, regardless:

#![no_std]
#![alloc]
#![feature(no_std, core)]

extern crate core as std;

mod mod_using_core { 
    use std::mem; // this will use libcore's mem module
}

mod mod_using_core_and_alloc {
    extern crate alloc as std;
    use std::mem; // this will use libcore's mem module
    use std::allocate; // this is a name resolution error, no module 'allocate' in 'core'
    // use self::std::allocate; // this will use alloc's allocate module
}

mod mod_using_std {
    extern crate std; 
    use self::std::string::String; // this will use the standard library's String type
}
ahmedcharles commented 9 years ago

Ah, I see. I missed the self:: before. Thanks for explaining.

alexcrichton commented 9 years ago

As a reminder,

:bell: This issue is now entering its cycle-long final comment period for stabilization :bell:

Ericson2314 commented 9 years ago

No idea why GitHub just gave me a notification to this, but very glad it did!

So to be clear here, I think in any individual crate, it's easy to work around any of the proposals thus far. The import ramification is the strengths and weaknesses of each affect what type of ecosystem arises, the compound effects of nudging users in different directions.

Specifically I worry about the no_std ecosystem. There's two basic issues here:


First, is the ability to limit oneself to same set of features and advertise that fact for others in the ecosystem.

While @nikomatsakis proposed use of --target works very well for specific architectures (naturally), often people want to write portable code intended for a certain "class" of architectures, including architectures/variants that may not exist at the time of development. I'd say the subsets of the creates behind the facade correspond to those classes pretty well. Maybe this a stretch, but if your code just uses core it's probably usable for real-time systems, vs if it uses core+alloc. Code that uses core+alloc on the other is might be good for a kernel (especially if alloc is changed so the allocator can always be chosen explicitly).

The other side is advertising. Because the no_std community is a small subset, and working in domains that traditionally suck at code reuse / abstraction (sorry...), we have an uphill battle here. Consider this quotes of @nastevens

My biggest difficulties have been around the Cargo support for no_std, not libcore itself. Right now there is not a way to search/filter libraries that are allocation-free. I've added a variety of keywords to my own crate to try and indicate that it uses only libcore, but an official marker of some sort would be fantastic.

The need here is after people have worked carefully limit their dependencies, it would be nice to proudly declare they have done so. Given the small size of the no_std community, this helpful both to get the word out, and even more so to make a library discoverable after any buzz subsided. Not to engage in self promotion, but my currently-in-limbo RFC (https://github.com/rust-lang/rfcs/pull/1133) would allow exactly for this.

The counterargument is that if the intended purpose is saying "this crate is good for real-time use", "this crate is good for kernel use", why not go after this directly with badges or whatever? Firstly, those are inherently subjective, whereas dependencies are not. Secondly, any concerns beyond "will this build with my project" such as time-complexity, space-complexity, interrupt-safety, etc, are things we are currently unable to verify, so claiming them is as bad as a more subjective quality--unverifiable either way. Tracking the dependencies at least captures whether something can be built with one's current project, letting one know definitively if there is a chance these this library can be used and those other properties verified.


Second, is the use of code in ways that the original authors did not anticipate. While the no_std community is a small portion of the overall Rust community, there will be a need/desire to use code not original intended for esoteric platforms. Here is where the std-behind the facade duplication backstabs us, as the only option is send out big, and thus hard to merge, pull requests (e.g. https://github.com/rust-lang-nursery/bitflags/pull/1) which basically sed everything.

Some might question whether code unintended for such platforms really is fit for them. But I'd argue it's nice to at least be able to check that fact. Also I am a big believer that the ease of writing good abstractions in Rust will such an unintended fit increasingly common compared to legacy languages. An anecdote: In the past year I've written Haskell that compiles to Verilog and Javascript, two targets that absolutely were not anticipated in 1989. In Haskell's case there are many libraries that are basically nothing but abstractions and work very well for obscure targets. I hope (and no-doubt others fear) that such creates will pop up in Rust, especially post-HKT.

Naturally, the subset plan works better for this--libraries only pay for what they use without any foresight or intervention on part of the developer.


@aturon An alternative would have been to not have std at all, and instead ship with a set of crates (libcore, libcollections, libio, etc) some of which work in kernel space. That would effectively make things "no_std by default". Personally, I regret not pushing harder on that alternative, but doing that now would be a massive breaking change.

Amen. This would have been the ideal solution. The first part, including my RFC, we get for free. Also normal users are forced (mua ha ha), to at least recognize when they start making more and more assumptions about the underlying platform, which solves the second. (If they just bulk extern crate things they don't need, well that is a much more lightweight PR to send them.)

I have some ideas on how we can get the best of both worlds without breaking changes, but I have some other things to do so I'll leave that for a follow-up post.

aturon commented 9 years ago

I'm going to use this as the tracking issue for no_std stabilization as well.

alexcrichton commented 9 years ago

@Ericson2314

First, is the ability to limit oneself to same set of features and advertise that fact for others in the ecosystem.

I definitely agree that there's some work to do on the Cargo/crates.io side perhaps to make no_std crates more visible, but otherwise it seems like your concerns are somewhat orthogonal to the design itself? In any world where we have a no_std-like concept it seems this sort of messaging would need to be solved regardless. Are there issues you have specifically related to the design of libcore which may be improved with a different design?

Second, is the use of code in ways that the original authors did not anticipate.

Note that this has been discussed at great length in this thread, and some salient points are:

Ericson2314 commented 9 years ago

@alexcrichton Yeah on the face of it my first point was suppose to be pro-facade, and my second point pro-subset. Overall the conclusion was suppose to be there are too many trade-offs between the currently proposed options to declare a clear winner.

I definitely agree that there's some work to do on the Cargo/crates.io side perhaps to make no_std crates more visible, but otherwise it seems like your concerns are somewhat orthogonal to the design itself? In any world where we have a no_std-like concept it seems this sort of messaging would need to be solved regardless. Are there issues you have specifically related to the design of libcore which may be improved with a different design?

Perhaps I mixed concerns and solutions a bit too much, the orthogonality was intended. My motivation was it can be useful both in the code and in the package meta data to be explicit about where/whether features like allocation, io, concurrency, etc are depended-upon. Leveraging the crates beneath facade for this is just a possible solution. Finally, in light of the discussion and revised topic, this was intended to be more about the existence of the facade and no std than core/core's contents.

some salient points are...

I wholly agree with the outer points. Re Number two, I'd just note the slight downside of the body of the code (below the uses) thus being slightly less clear about what comes from where.

Ericson2314 commented 9 years ago

So to follow up, my tentative proposal is to have our cake and eat it too! Specifically, have the user compile std---wait, this won't be as crazy as it sounds :).

If we move everything into crates behind the facade, std ought to just be re-exports, and thus compile quickly with a stable compile. Furthermore it would have all the target cfgs to get the subset proposal.

For bare rustc usage, we'd just allow to link anything in the sysroot. But for Cargo, we can also make Cargofile for std that has all the conditional dependencies so that when cross compiling Cargo knows exactly which crates behind the facade need to be built for the given target.

For those of us working on esoteric targets, it's probably best to avoid std altogether and just use the crates behind the facade, even if most of std is going to be used. Then you're code is super explicit about what sorts of platform/features it depends on, and where. Additionally with my RFC all that information is reflected in the Cargofile for advertising purposes. Basically, live in a world in which we had taken the "std is a collection of libraries, not a library" route.

For normal users, or those not wanting to wait for all the crates behind the facade to be stabilized, just use std. Because of the subsetting behavior, your code will still be usable by those working behind the facade if you happen to confine yourself to a subset.

[N.B. it would be convenient to, in target CFGs (or something similar to avoid the layer violation) list which crates behind the facade are usable. The purpose of this is a kernel for, e.g., x86-64 should use a custom target so that if they link a library written using std, it won't try to build/use normal std for the library with all the UNIX-dependent features. I don't see this as too much of a burden was one should use a custom target anyways for a bunch of other reasons, just now this becomes essential.]

diwic commented 9 years ago

Sorry for throwing in an idea at the last minute, but I don't think exactly this has been suggested earlier:

About the syntax - instead of #![no_std], one could imagine e g #![custom_std(core)], #![custom_std(core, alloc, collections)] that would select the requested parts of std only. That way we can keep the core crate as a hidden implementation detail.

About the split - I think it would be helpful if we also split core into at least base (integer types), panic, and float parts given the exported symbols mentioned earlier in the thread. It seems useful to be able to be without panic and float when targeting really small processors (e g without floating point support) and with very small memory (no unwind code overhead). Separating the panic away might be controversial though, so feel free to disregard if it's too difficult.

Ericson2314 commented 9 years ago

@diwic I'd be down with that, especially if we could then also do std-components = ... in the Cargofile or analogous.

nikomatsakis commented 9 years ago

@diwic

About the syntax - instead of #![no_std], one could imagine e g #![custom_std(core)], #![custom_std(core, alloc, collections)] that would select the requested parts of std only. That way we can keep the core crate as a hidden implementation detail.

It seems like you shouldn't have to name core, since it contains so much stuff (e.g., the Copy, Sized, and Fn traits) that the compiler relies upon. (Compiling without core, or with a different core, is just not supported.)

It'd be sort of nice if #[custom_std] could arrange things such that you still got to just do use std::foo and it worked. Sadly this isn't really possible in any obvious way. That is, you can do extern crate core as std, but if you want routines from alloc you can't "union" core and alloc into one "pseudo-crate".

posborne commented 9 years ago

@Ericson2314

If we move everything into crates behind the facade, std ought to just be re-exports, and thus compile quickly with a stable compile. Furthermore it would have all the target cfgs to get the subset proposal.

For bare rustc usage, we'd just allow to link anything in the sysroot. But for Cargo, we can also make Cargofile for std that has all the conditional dependencies so that when cross compiling Cargo knows exactly which crates behind the facade need to be built for the given target.

Working in embedded systems (a HUGE market where Rust is desperately needed), a solution like this seems very appealing. In embedded systems, the two following environment constitute a majority of the new development work happening:

  1. An embedded Linux environment where use of all of std is OK but which requires cross-compilation (usually to ARM). Use of dynamic memory on these targets is usually considered acceptable but high reliability is still expected.
  2. An embedded target (e.g. 32-bit ARM Cortex-M MCU) where no_std (or a more limited subset of std) is required across the board. The global heap (e.g. traditional dynamic memory) should not be used in these environments due to its non-deterministic nature (and memory fragmentation).

The only way we can currently target these targets right now in systems like zinc is because that framework includes a bunch of hacks for users. For Rust to gain traction in embedded markets, however, I believe we will need to modify the language ecosystem so that those hacks (and the frameworks implementing them) are not required. It's hard to make an argument for use of Rust today in these environments (particularly MCUs) given the current state of things.

The main hacks included in zinc now are the following:

  1. The code running on the target itself does not really include any dependencies outside of the code in zinc itself.
  2. We use several unstable features right now. That is understandable and probably won't change in the short term but something that should be worked toward.
  3. To include core, we use https://github.com/hackndev/rust-libcore
  4. We use rlibc (this is probably OK): https://github.com/hackndev/rlibc. This wouldn't really be necessary for most embedded targets as we can use something like newlib nano. For pure rust systems, there are probably some savings with using rlibc.

Things have certainly improved since when everything in Zinc was built using Rakefiles. I think that cratification and moving toward a std facade would solve a lot of problems for less traditional (but critical) environments.

Ericson2314 commented 9 years ago

@posborne I had talked to you about my RFC long ago, which alone would remove the need for hackndev/rust-libcore. I think we are both in agreement that no matter what route is taken, Cargo needs to know about the crates behind the facade / subset of std being used, in order to work well with zinc-like use-cases.

Assume that the build system issue are taken care of either way, and assume also that either the creates behind the facade or equivalent subsets of std can be used or excluded explicitly and portably. Do you prefer a unified namespace, or separate (core, alloc, etc) namespaces, or not really care (those assumptions covering the most important concerns)?

I was thinking that those assumptions cover the most import practical concerns, but that for the zinc crowd at least, the balkanized namespacing itself is valuable as mental reminder of what assumes what. The std namespace would be for those that don't care (and backwards comparability).

Conversely, we could keep the crates behind the facade unexposed, and have the std cargofile have explicit features instead of going off the target config. This would basically be @diwic's interface with my implementation, which I think sidesteps @nikomatsakis's concerns. I am not sure what to do for bare rustc invocation in that case, but maybe exposing all the flexibility for that is not important as rustc+custom build system already allows one to achieve everything with enough effort.

alexcrichton commented 9 years ago

@Ericson2314

Reading over what you're thinking, isn't that basically what the facade is today? It sounds like you'd propose moving out the entire standard library into a facade crate, but we're certainly at liberty to do so today if we like. It also sounds like we're still shipping some binaries, and even if the "glue of std" is stable it wouldn't solve the easy-cross-compile problems because you still wouldn't be able to compile the source? (unstable code). Otherwise the facade already buys you the ability to mix and match components underneath the hood, we're able to break apart libraries at will.


@diwic

I think what you're proposing is basically the subset proposal on this thread where it takes subslices of std and gives those to you. You can do this with the facade, however, with explicit extern crate annotations, you simply just don't access them all through the same std:: name. In other words, I think that the facade design is not hindering any use cases, it's just a way of expressing each use case.

Unfortunately in the case of splitting core up, support for panicking is required basically everywhere (e.g. a % b requires panic support), but if it's a problem in terms of memory usage that's a bug that should be fixed! It is not expected that small embedded contexts will actually have stack unwinders. Additionally floating-point support can just be removed by not using it and then linking with --gc-sections. I'd also prefer to move some of it externally, but coherence doesn't allow us to do that right now.


@posborne

You've got some interesting use cases! I think the facade definitely fits in nicely with them, but I'd be curious to hear more about the difficulties you're running into (perhaps elsewhere than this thread), because like you I definitely share enthusiasm for pushing Rust deeply into the embedded space! It sounds like some of your concerns are Zinc-specific or perhaps build-system-related though rather than pertaining to the design of the facade? I'd be curious to dig in more though.

Ericson2314 commented 9 years ago

@alexcrichton

Reading over what you're thinking, isn't that basically what the facade is today?

Yes it is both the facade we have today and the subset plan.

It sounds like you'd propose moving out the entire standard library into a facade crate, but we're certainly at liberty to do so today if we like.

True, which is convenient.

It also sounds like we're still shipping some binaries, and even if the "glue of std" is stable it wouldn't solve the easy-cross-compile problems because you still wouldn't be able to compile the source? (unstable code).

Yes the std-glue doesn't help with cross compiling with a stable compiler. I just wanted to point out that there was no regression; stable not being able to use std would be quite bad :)!

The big difference is that by using a custom target, one can "trick" code using std to just get a portion of std. If the unavailable things were used, well then tough luck, but if they weren't, everything just works. It's sneaky way to allows using normal code in esoteric contexts without modification.

diwic commented 9 years ago

@nikomatsakis

It seems like you shouldn't have to name core, since it contains so much stuff (e.g., the Copy, Sized, and Fn traits) that the compiler relies upon. (Compiling without core, or with a different core, is just not supported.)

That's fine; the reasons I have it there are:

  1. The RFC mentions a !#[no_core], not mentioning core could be the same as specifying no_core in the RFC - at least for now.
  2. We might want to split core even further in the future (e g to split out panic or float handling) - specifying core would then suit to do what core does today.

It'd be sort of nice if #[custom_std] could arrange things such that you still got to just do use std::foo and it worked. Sadly this isn't really possible in any obvious way. That is, you can do extern crate core as std, but if you want routines from alloc you can't "union" core and alloc into one "pseudo-crate".

I naively thought it would be as simple as autogenerating this code:

pub mod std {
     extern crate core;
     pub use core::*;
     extern crate alloc;
     pub use alloc::*;
     pub mod prelude {
        pub use core::prelude::*;
        pub use alloc::prelude::*;
     }
}

...and some compiler magic to make sure std::prelude ends up being the prelude?

thepowersgang commented 9 years ago

Just to put my two cents in - As a developer of a rust-based OS, the current model of #[no_std] importing libcore seems to work quite well. This can be easily stabilised as is, while leaving the option open for a #![custom_std()] attribute that does as @diwic suggests

core_float is the only real problem for OSDev work (due to the x86_64 ABI requiring use of SSE registers for floating point returns, but it is desirable to disable SSE code generation in kernel code)

nikomatsakis commented 9 years ago

On Fri, Nov 06, 2015 at 10:01:05PM -0800, diwic wrote:

I naively thought it would be as simple as autogenerating this code:

pub mod std {
     extern crate core;
     pub use core::*;
     extern crate alloc;
     pub use alloc::*;
     pub mod prelude {
        pub use core::prelude::*;
        pub use alloc::prelude::*;
     }
}

...and some compiler magic to make sure std::prelude ends up being the prelude?

Well hmm, maybe you're right. :)

eternaleye commented 9 years ago

I just figured I'd chime in on @nikomatsakis' bikeshed, and point out that the C/C++ world has long-since had a term for what is currently called #![no_std] in Rust: "freestanding". In addition, "freestanding" has the benefit of being both a "positive" notation (avoiding contortions like "non-#![no_std]" as seen in a message above) and having a natural reading when combined with other things.

For example, if someone wanted libcore + liballoc, the notation #![freestanding + alloc] is immediately obvious as to its meaning, to steal a syntax from an earlier post.

This would work especially nicely with the above idea of synthesizing std rather than injecting an import of it.

One further thing is that I'm personally not especially convinced by the allocator story as a long-term approach to susbstituting components of std - and I feel that synthesizing std offers the opportunity to go one better.

In particular, #![freestanding(core, net(lwip))] could become

mod std {
     extern crate core;
     pub use core::*;
     extern crate lwip as net;
     pub use net::*;
     pub mod prelude {
        pub use core::prelude::*;
        pub use net::prelude::*;
     }
}

Heck, aside from being a shebang, this can be done in a procedural macro (half-pseudocode due to collisions &c):

macro_rules! freestanding (
    ($($component:ident($from:ident)),*) => (
        mod blarg {
            $(
            extern crate $from as $component;
            pub use $component::*;
            )*
            pub mod prelude {
                $(
                pub use $component::prelude::v1::*
                )*
            }
        }
    );
    ($($c1:ident($i1:ident)),*, $component:ident, $($c2:ident($i2:ident)),*) => (
        freestanding!( $($c1($i1)),*, $($c2($i2)),*, $component($component) );
    );
);

However, if implemented in the compiler, it can go further - interpret #![freestanding(foo)] as "I need a foo, but I'm not picky about which one", enforce that #![freestanding(bar(baz))] and #![freestanding(bar(qux))] are mutually-exclusive in a similar way to the only-one-allocator linkage rule, etc.

Of course, at that point the names of components behind the facade start looking an awful lot like "traits for modules", and #![freestanding()] starts to look like a variadic type constructor for implementations of std...

steveklabnik commented 9 years ago

So, libcore having floating point involved has come up a few times, and it'd be nice to think about that before we stabilize. In two contexts:

The former is specifically about what "no dependencies" means, and the latter is about confusion that results. Said post lead to this issue: https://github.com/rust-lang/rfcs/issues/1364

It'd be nice to address this in some fashion. OS development is a big part of no_std, and having to use yet another subset of core for this is not ideal.

alexcrichton commented 9 years ago

@eternaleye

I tend to agree on that renaming #![no_std] to "something positive" sounds like a good idea, but I'm not sure what's going on with the synthesis of a std module and this new parameterized attribute. If you want core + alloc, why not just say extern crate alloc plus the "only core attribute"? That way we're not inventing any new attribute and it's just one less thing to remember.

One benefit could perhaps be the addition of alloc and core both into the prelude, but this sounds a lot like custom preludes which may be best to land as an orthogonal feature. Crates elsewhere in the ecosystem want their own custom preludes as well, so it's be good to ensure that there's a unified mechanism everywhere for that.

Ericson2314 commented 9 years ago

@alexcrichton I think people like the module-generating idea so that everything is under the std namespace. I'm now suspicious whether that will work so easily given we have things like core::sync.

Also, with to your new RFC https://github.com/rust-lang/rfcs/pull/1361 my cargoize-std idea should be much easier, thanks!

briansmith commented 9 years ago

According to the code in slice.rs, the feature core_slice_ext is tracked by this issue. What will happen with core_slice_ext? Should SliceExt be removed?

nikomatsakis commented 9 years ago

So thinking about the idea of synthesizing a "union std" module -- I think it's probably not the best place for us to start. I worry it will be a leaky abstraction, and hence people will be more confused, whereas if we just explain that std is a convenient facade, but you can add #![use_std] (or whatever) and access its components parts individually, it will... not be confusing. Of course such a macro could be used in crates.io or something as a convenient migration aid.

alexcrichton commented 9 years ago

In terms of bikeshedding, how do others feel about the name #![use_std] as the attribute to trigger linking to libcore instead of libstd by default? I think @nikomatsakis and @eternaleye are right in that #[no_std] isn't the "best name", but I'm at a bit of a loss of what else to name it!


@briansmith

Yeah the plan would be to stabilize the extension traits. They're all imported in the prelude by default, however, so they shouldn't need to be imported most of the time.

posborne commented 9 years ago

In terms of bikeshedding, how do others feel about the name #![use_std] as the attribute to trigger linking to libcore instead of libstd by default?

Correct me if I am grossly misunderstanding what is meant by #![use_std].

#![use_std] strikes me as being a somewhat confusing name for not (necessarily) using/linking std. #![no_std] is terse and negative but not (too) misleading. Adding an attribute that sounds like the opposite kind of thing but which does the same as !#[no_std] would be confusing to me.

I could see #![freestanding] (does not include code for pulling in core or std) and/or #![use_core] (link against core and pull in prelude) as being options.

alexcrichton commented 9 years ago

Oh wow that was a mega typo on my end, I meant #![use_core] not use_std, sorry!

bluss commented 9 years ago

It would really be much cleaner if the extension traits could be removed. I guess there will grow up quite the ecosystem around just core.

posborne commented 9 years ago

Oh wow that was a mega typo on my end, I meant #![use_core] not use_std, sorry!

Ah, that makes much more sense. Would the behavior for #![use_core] be different than #![no_std] at all?

ranma42 commented 9 years ago

I agree that #![no_std] is not particularly good, but -nostdlib could be imagined as a precedent.

The main issue I see with #![use_core] is that the it does not seem to imply in any way that it is limiting the available features. To me, it resembles too much use core, which would instead pull in additional items.

I would rather have it named #![core] or #![only_core] or something like that.

diwic commented 9 years ago

@nikomatsakis

So thinking about the idea of synthesizing a "union std" module -- I think it's probably not the best place for us to start. I worry it will be a leaky abstraction,

I suppose 'synthesized union std module' refers to my proposal...so I just wanted to add that if the leaky abstraction problem is that we have things in (e g) core that should only be used from alloc and not from end-user programs, that can be resolved by making a for_custom_std module inside core where you have only the stuff you want to expose to end-user programs, and then have a pub use core::for_custom_std::* instead of pub use core::*.

eminence commented 9 years ago

the name #![use_std] as the attribute to trigger linking to libcore instead of libstd by default

It feels weird that "use std" means "don't use std, use core instead".

Note: I've not been following this discussion closely. I apologize if this discrepancy was already discussed, but I thought it might be useful to add an opinion of someone "from the outside"

posborne commented 9 years ago

@eminence See https://github.com/rust-lang/rust/issues/27701#issuecomment-155958826. @alexcrichton intended to write #![use_core].

eminence commented 9 years ago

Thank you! I'm sorry, I thought github was showing me the latest comments, but apparently that wasn't the case. +1 for #![use_core]

alexcrichton commented 8 years ago

@ranma42 one downside of #![core] is that it kinda looks like you're declaring "this crate is core" when it in fact is just linking to it. #![only_core] sounds plausible though!

alexcrichton commented 8 years ago

A point against #![use_core] (but not too strongly) is that all programs using std are already using core (e.g. linking to it and using code from it), so it's kinda weird for the attribute to actually imply that you're basically just using the core instead of std prelude by default.

phil-opp commented 8 years ago

I like #![no_std] more since it's essentially an opt-out for the default standard library. #![use_core] sounds like it's an opt-in for some additional functionality. And I don't think renaming it adds enough value to break every no_std crate and documentation (including blog posts). There are enough outdated posts about Rust out there.

Ericson2314 commented 8 years ago

So it seems there is consensus that just using the crates behind the facade as is is fine. I have no problem with with that, but that brings us back to things mentioned earlier in this thread (the awkwardness of things being available from multiple places (std and core); what to do about macros; etc) that got overshadowed by the talk of subset std.

I'd feel better if there was some agreement that it is recommend or at least acceptable stylistically to use things from core even when not using #[no_std] (or whatever we rename it).