-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shall we require no_std compatibility? #77
Comments
This can be done with
This can be done with |
If we're going to require no_std support, we should probably standardize on a list of no_std crates to replace common functionality in the standard library. For example, what should we use instead of |
I took another look at this in light of @Manishearth's comments. Advantage 1: Encourage Best PracticesI feel that A stated goal of ICU4X is small code size and constrained resources; The pieces of the standard library that do exist in Advantage 2: Reduce Debugging MachineryIn terms of advantage number 2: extern "C" {
#[allow(improper_ctypes)]
fn alert(s: &str);
}
#[no_mangle]
pub fn greet(input: &str) {
let mut message = String::new();
message.push_str("Hello, ");
message.push_str(input);
message.push_str("!");
unsafe {
alert(&message);
}
} See my results: no_std versus std. Advantage 3: Recompile Standard LibaryI was under the impression that There's one exception here. If you want to use std::collections::HashMap, in a Let me also go over some disadvantages to requiring Disadvantage 1: Harder to Code@hsivonen brought up the point that requiring I brought up the point that the no_std_compat crate makes it such that you can depend on the same old standard library features with the same syntax, via Regarding coding style: this is by design, and is Advantage 1. Rust makes it really easy to go overboard with the standard library, and we want to discourage that practice in ICU4X. However, my opinion on this issue could be shaped by further experience of things that you can no longer do without Disadvantage 2: Easy to Add LaterIf we restrain ourselves from not using standard features like RegEx and std::io, then yes, adding Disadvantage 3: Best would be to avoid the alloc crateMy proposal for This is a valid concern, but it falls in the same bucket as Disadvantage 2. If someone comes to us and wants to eliminate the In conclusion: clearly I am in favor of requiring What do people thing? |
We don't have regex in the stdlib. The Rust stdlib is very small, it basically has:
The traits are free. We want to be able to use the collections. I don't see us accidentally using IO/fs primitives for the kind of stuff we're doing. Someone might pull in concurrency stuff but that should be easily caught in review, and I can imagine us wanting to use things like Most of Rust's "footprint" ends up being in the other libraries you pull in, and we can try and keep a tight grip on that via CI checks that require whitelisting dependencies. Worth noting, I do not think
My point is more that |
I have much less experience in this domain but I also feel like we should rather identify a subset of the project that we want to set |
Hmm, I was under the false impression that we did. @nciric
Noted. I count this as a strike against Advantage 1.
This is a good idea, and is something we should do regardless of whether we are no_std or not. To recap the advantages of no_std from my point of view:
Manish has poked holes in most of my advantages arguments (thanks for keeping me honest). On the other hand, I haven't really seen a disadvantage that is compelling. There is also one more item I wanted to add as an Advantage. Advantage 4: WebAssembly EcosystemI think this is how the idea of no_std first got in my head. I was reading various blog posts recommending no_std as a good option for WebAssembly. Here are some sources: Rust-WASM Bookhttps://rustwasm.github.io/book/reference/which-crates-work-with-wasm.html
WeeAllochttps://github.com/rustwasm/wee_alloc
https://docs.rs/wee_alloc/0.4.2/wee_alloc/#using-wee_alloc-as-the-global-allocator
https://www.reddit.com/r/rust/comments/dp1omc/rust_2020_exploit_dominance_in_web_assembly_and/
|
@fitzgen Do you consider no_std+alloc a best practice for writing a WebAssembly-compatible Rust library? |
The disadvantage from my POV is mostly that it's annoying to work with, especially since we need to pull collections back in as crates, losing interop if we ever need to e.g. return a hashmap. It's also just ... weird, it's off the beaten path which means there will be a lot of crates we may want to use that could theoretically work with no_std+alloc but do not do that because no_std+alloc is a rare use case. You're right about the wasm thing, but also that's mostly a quick rule of thumb: if we avoid fs/io APIs and threading we're fine. And we won't need fs/io except in some data providers, but we can write wasm-specific web-sys data providers if we need. Threading would also likely be optional perf features if we use it at all. So I just don't see us accidentally using features that make wasm hard. I would absolutely defer to fitzgen on the wasm specifics though. |
This is solvable. When the
Don't know about the full ecosystem, but Serde supports no_std+alloc (which I use in #61). Hopefully our dependencies are relatively minimal, so if we encounter any such crates, we can add no_std+alloc support upstream. |
I do not, except in the relatively rare case where library always makes sense as a no-std+alloc library (e.g. For example, if a toml crate has a method to parse toml from a file and another method to parse from a slice, it probably uses
|
Thank you for your time and reply. My responses are below. I really don't mean to sound stubborn, and I apologize if I'm coming across that way. I know I do not have the same level of experience in this subject as the others on this thread. However, I feel that some of my points in favor of no_std have not been adequately addressed, and I am not convinced by the arguments against no_std.
But, this is exactly what serde-json is doing. It feature-gates https://github.com/serde-rs/json/blob/d13374812226f20c9d194bcf5aa1bcb36f759bd6/src/de.rs#L2309 That's the practice I think would be good to adopt in ICU4X; it forces you to think about what features are useful for native Rust clients, and what subset to carve out for environments where I/O or threading is unavailable. That's a good thing, not a bad thing. Furthermore, ICU4X is low on the stack. We don't want a lot of dependencies. If we do want to add a convenience feature that pulls in a dependency, we probably want to feature-flag it, in which case it is easy to make it std-only. In fact, I see the dependencies argument as one in favor of us adopting no_std. The no_std movement in Rust appears to have a fair bit of steam. We're building a low-level library intended to be used by hundreds of clients. The chances of someone coming to us wanting to use ICU4X in no_std (with or without alloc) seem rather high. By not building with no_std as a target audience, wouldn't we be contributing to the problem of Rust ecosystem libraries not being no_std-ready? If we were building a leaf application where we don't expect many dependents, no_std may be overkill; but, when we're talking about a low-level library, I think the conversation is different.
I've written a fair bit of code already as no_std, and I did not find my development velocity to be significantly hindered. The no_std ecosystem, especially with the help of crates like no_std_compat, makes no_std development basically the same as std development, except with "as designed" constraints such as requiring that std::io goes behind a feature flag. |
wrt regex - I imported regex crate into a super simple app and it blew size
to 640KB. In our previous meeting we came to conclusion that it's probably
Unicode data that's at fault, not the actual regex code/ascii data.
I don't know if it's related to std no_std discussion.
суб, 16. мај 2020. у 18:35 Shane F. Carr <notifications@github.com> је
написао/ла:
… Thank you for your time and reply.
My responses are below. I really don't mean to sound stubborn, and I
apologize if I'm coming across that way. I know I do not have the same
level of experience in this subject as the others on this thread. However,
I feel that some of my points in favor of no_std have not been adequately
addressed, and I am not convinced by the arguments against no_std.
------------------------------
... using dependencies will get even harder. For example, if a toml crate
has a method to parse toml from a file and another method to parse from a
slice, it probably uses std and doesn't feature gate the file-using method
behind a "std" cargo feature.
But, this is *exactly* what serde-json is doing. It feature-gates
from_reader (which uses std::io) on the std feature.
https://github.com/serde-rs/json/blob/d13374812226f20c9d194bcf5aa1bcb36f759bd6/src/de.rs#L2309
That's the practice I think would be good to adopt in ICU4X; it forces you
to think about what features are useful for native Rust clients, and what
subset to carve out for environments where I/O or threading is unavailable.
That's a good thing, not a bad thing.
Furthermore, ICU4X is low on the stack. We don't want a lot of
dependencies. If we do want to add a convenience feature that pulls in a
dependency, we probably want to feature-flag it, in which case it is easy
to make it std-only.
In fact, I see the dependencies argument as one *in favor* of us adopting
no_std. The no_std movement in Rust appears to have a fair bit of steam.
We're building a low-level library intended to be used by hundreds of
clients. The chances of someone coming to us wanting to use ICU4X in no_std
(with or without alloc) seem rather high. By *not* building with no_std
as a target audience, wouldn't we be *contributing* to the problem of
Rust ecosystem libraries not being no_std-ready?
If we were building a leaf application where we don't expect many
dependents, no_std may be overkill; but, when we're talking about a
low-level library, I think the conversation is different.
all you're doing by using no-std+alloc is making development harder for
yourself
I've written a fair bit of code already as no_std, and I did not find my
development velocity to be significantly hindered. The no_std ecosystem,
especially with the help of crates like no_std_compat, makes no_std
development basically the same as std development, except with "as
designed" constraints such as requiring that std::io goes behind a feature
flag.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#77 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AA7GEKXZ7KFUMB4AZWDJTZ3RR45PZANCNFSM4M3CCFAA>
.
|
Serde is super low level on the stack, it's a foundational crate in rust and as such it can expect to be used everywhere.
This is the I'm only arguing against supporting the Overall it seems to me that your arguments do support choosing to try for Concretely, my proposal is:
I find drawing this line to be far more useful than just doing |
Thanks for the post about the three-tiered system. That makes a lot of sense and is a good way of looking at this problem. Regarding Allocation and the non-alloc no_std tierMy experience is that much of ICU's functionality can be written using "stack only" data structures, without requiring a memory allocator. However, there's always going to be some locale that has a 100-byte month name, exceeding the limit of the stack structure. In ICU, we usually fall back to a heap allocation in this case. What do you suggest as a best practice to handle such situations?
Do you further suggest that we try to use the Regarding the no_std+alloc tierHere's how I see the use cases for the three tiers:
Manish is advocating for combining tiers 2 and 3, and Fitzgen said the same. I'll go ahead and rehash my concrete reasons why I think keeping tiers 2 and 3 separate might be an advantageous solution:
On the second bullet about smaller binary sizes, I know you've suggested About dependencies not being compatible with |
I think having We could try doing this via a shim crate. It's also possible to start off first with the "no_std users don't get this" and gradually make things compatible.
I don't think it really succeeds in this. It doesn't do this for dependencies, and it enforces a very rough best practice instead of the finer-grained stuff we probably need.
Rust will not include things we don't need, this doesn't affect binary sizes. It only affects in the sense that it discourages us from pulling in new things.
I haven't really suggested xargo for this, I suggested it for compiling the stdlib with different flags, which you previously (incorrectly) felt was possible via
Not if we try and do the allocation-fallback thing suggested earlier. We don't get this for free. We get this for free for our crate, and then need to worry about it in dependencies. Tooling around this is largely focused around |
@fitzgen stated that he does not think I'd prefer to start with (3) and introduce (1) where needed, as Manish suggests. |
Is there prior art for this?
OK. "I'd rather not be in a position of pioneering it" is sensible. I still think |
Not that I'm aware. We'd probably want either a panicky smallvec/tinyvec variant, or something that is unconditionally vec on std builds and unconditionally a panicky array on non-std. I have definitely seen no_std ecosystem crates that implement the "panicky array" stuff before which we can join up, I just don't recall where. |
We discussed this subject at this week's ICU4X meeting. Main conclusions:
|
Being compatible with
#![no_std]
is important for running on low-resource devices. The benefits of no_std include:-Z
can be used to compile standard library codeIn a no_std environment, we would still depend on the
alloc
crate. A lightweight allocator such as wee_alloc can be used when necessary.The text was updated successfully, but these errors were encountered: