-
Notifications
You must be signed in to change notification settings - Fork 1.6k
[Draft] RFC: Console Input Simplified #3183
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
Conversation
I like the idea. Input and output would be more consistent if |
In the second link, they closed the issue with the message: This feature has been baking in several libraries (such as text_io) for several years, so maybe I could suggest the version from one of these crates? |
I think use std::io::BufRead;
std::io::stdin().lock().lines().next().unwrap().unwrap() Also, being able to write this kind of thing without having to call |
Something that is not clear in the guide-level explanation of That's specially confusing because But I think this just means that And well, |
A reason for Python's prompt line is that the input needs to be flushed. Just going for print!("Name? ");
let name = input!(String); doesn't show the prompt until after the user has pressed Return. A |
On the "drawback" side, I'd add that it is putting a possibly sub-optimal solution into the standard library. Printing to stdout is straightforward, and Reading from stdin does not have an analogon for "simple and does almost everything you want": The terminal emulator usually gives some line editing capability (like erasing the last character), but even moving back with the cursor to change anything but the last letter is not provided. The Python version you cite for comparison does not do that either, but as soon as the Python readline module is loaded (which is the case when the interactive interpreter is used), readline's input takes over Python's input function and provides not only cursor movement but also history. Other than first-week introduction-to-programming examples, I think that most developers will have unhappy users with a bare terminal input, and would be better off using rustyline or something like that right away. |
Yes that is why in the RFC I state that it would be better for However, I have been revising my RFC and trying to come up with a better API, and found the one found in the |
I don't think they would be unhappy, I think they would simply just install a more complex crate if they need more features. Having a simplified input system would simply make input for smaller programs, teaching, etc easier. I understand what you mean however. |
The users are in no position to updated that -- unlike Python where you can just
I wouldn't want to be in either of these three situations. If we go ahead with this, I think that the input functions should described as "for experimentation and educational purposes", and their documentation should recommend using platform specific method or third party abstractions when not falling into these categories (possibly with concrete suggestions). Then the above deadlock has a clear way out. |
Responding to the three-party triangle:
This is just like the |
I have just pushed a commit to this RFC improving the example implementation. It now only reads up to a space for Please let me know what you think of these changes. |
See also rust-lang/rust#75435 and this draft RFC. |
While there are other RFCs related to #3183, none of them solved the problem. |
This RFC is great for using rust in competitive programming. People still widely use C/C++ in that field, because languages such as python or java will exceed time/memory limits in hard problems. So Rust is a great fit for this field, but lack of a good input system blocks the usage of Rust. And this RFC is the only possible kind of solution for it because:
If |
Yeah this is another good example of where having a simplified input system would be useful. My concept for the implementation is also just a mere example, I was thinking that it might be better to implement the input functions/macros that an existing crate has like |
I decided to mark this as a draft since we are still deciding on an implementation. Please suggest any ideas if you have any. |
I've been using Rust for competitive programming for a while (while not being competitive myself). What is usually done for common tools is to have a template that you would use to solve each problem, with Rust I have indeed had to think about the parsing issue. My approach has been to rely on generics and output structure instead of a macro: templates/rust.rs. I think we could make this RFC more ambitious:
let name: String;
let weight: u64;
let child_id: usize;
scanln!("name: {}, weight: {}, child_id: {}", &mut name, &mut weight, &mut child_id); I still probably miss a lot of things. |
I like your idea, it makes it more powerful. However, how would the string work here? When you call I will attempt to write an implementation for this too and once I get it working I will post it here. With regards to your first idea, I think we should also propose a |
I like I'm not a fan of Still seems like this should be a create to start with though until it's well tested rather than an RFC? |
Yeah I'm thinking of just turning this into a crate for a bit while I try to find the best API for this. At the moment, I am experimenting with something that looks like this: fn main() {
let age: u8 = scan!().unwrap();
// we can read with a pattern aswell
let name: String = scan!("name: {}").unwrap();
// im hoping to get something like this working
let person: (String, u8) = scan!("{}, {}").unwrap();
} What do you think? |
@undersquire said
Why not put the variables as arguments to the |
Maybe I could support both, because to me it seems easier to just write the types and get back a tuple than having to declare each individual value first. I will add the implementation for both into my crate for testing so we can experiment with it and see which one (or maybe both versions) is the best. |
After thinking about it a minute more, I think I would actually love to see something like this, with the type specified in the braces: let (name, age) = scan!("{String}, {u8}"); // returns `Result<(String, u8), Error>` And maybe allowing something like this: let (name, age);
scan!("{name}, {age}") // returns `Result<(), Error>` |
This would be nice, but unfortunately not likely possible. I have been experimenting with macros and I tried to create something like this but I was unable to. Maybe someone else here more experienced knows how to implement this. |
RFC 2795 does something similar. Have you looked at how that's implemented? |
This seemed to be implemented at the compiler level, as the compiler could read in the format string at compile time and pick out the variable names. So I guess if the compiler developers were willing to implement this at that level then we can have this API. |
It isn't complete, but here is a link to the repository of the crate I am writing for testing implementations for this RFC. (NOTE: This isn't functional at the moment, should be by the end of tomorrow). This is mainly for anyone who wants to contribute to the implementation or look over how I am implementing it. |
Why does the outcome of #67 not apply here? I've no problem with there being discussion over design, but it shouldn't be taking place in this repository until there's something that could be adopted nearly verbatim. |
Outcome of #67 does apply here, but now there is an implementation being worked on unlike before. The previous RFC was closed due it not being a library and couldn't be tested. Several libraries have been created since then and I would assume things to change in 7 years. Edit: Also because the problem still exists. Nothing has been done to provide simple input like there is in pretty much every other language. |
If there's already a library doing this, why is there so much uncertainty in this thread? New ideas are being thrown out such as a |
That's just opinion based. Some people like |
I understand what you mean, however the main reason I am keeping this RFC open even though the implementation isn't fully agreed upon is because otherwise this will just die out like the original RFC #67 you mentioned. That RFC was opened 7 years ago and yet we still have nothing. If by keeping this RFC open it keeps people active on the issue then there is a good chance it will be solved. EDIT: I am going to draft this RFC for now since there isn't a decision on the implementation yet. |
I agree with @dlight's comment:
Building an interactive console game is a great way to familiarize yourself with a new language and So I think the suggested I however do not see the appeal of the suggested let age = input!(i32).expect("Invalid age!"); That in my humble opinion is strictly less readable/desirable than: let age: i32 = inputln!()?.parse().expect("Invalid age!"); I don't consider a helper to parse multiple values from a string to be something that needs to be in the standard library. I think such parsing utilities should be best left to crates. tl;dr: I think the best argument for this RFC (making Rust more accessible to beginners) would be better addressed by an |
I think that a simpler function like Should I create a poll to decide whether we should do a simpler or more advanced approach and just let it to a vote? |
It doesn't work though. Go on any C or C++ forum or Stack Overflow. The questions will be full of confused beginners abusing |
I've been neglecting commenting on this thread because I've wanted to read it all before I say things, but at this point I don't have the time so I'll just list my thoughts here, whether they're repeats or not: Basically, I've felt for a while that That said, there is clearly a need for some form of Another thing that I think that I personally think that the order of steps should be to replace |
@undersquire Thanks for getting this going. It seems to me that the idea as it currently exists in your repo is heading in a different direction than what the RFC started with. I see a couple of distinct needs here:
I don't have strong opinions on (1): I think it's hard to get this interface right and it deserves its own RFC and discussion. I would really like to separate it from (2). For me the motivating example is Guessing Game from the Rust book, which avoids trying to do anything clean code-wise or usage-wise with getting a guess because zomg Rust line input. I have previously suggested standardizing on the functionality of my let line1 = input!();
let line2 = input!("{}: ", 2); The If people like this idea we can try to get together an RFC for it. I would then suggest a separate discussion of (1). I think having a solid |
I agree that user-friendly line input is a separate issue from parsing/scanning and should therefore be discussed separately. Which is also the reason I opened my RFC #3196 for which I explicitly declared parsing/scanning as out of scope. You're of course welcome to comment on my RFC :) Please however mind that my RFC proposes a function as opposed to a macro and that the function vs macro matter has already been discussed extensively. |
I actually made a poll a little while ago to see what the community prefers, and it seems that they prefer that the standard library offered both simple and advanced input APIs. So I think that the best course of action is to get #3196 implemented/accepted. From there we can look into a more advanced API for the cases where you need more advanced input. I am uncertain what it would look like but I think a dedicated RFC for it will spark a discussion. |
Who participated in the poll? |
I posted it to the official Rust discord and another unofficial one, and r/rust |
Well why not here? I would have been glad to participate, had I been aware :( |
I thought about posting it here but didn't think many people would have voted anyway. Posting it on the active discords and subreddits guaranteed a larger sample size. If you want, you can still vote :P |
|
Implement simple macros to make console input simple, just like how console output via
println
is very simple and convenient.Rendered
EDIT: This RFC is not complete and the concept for the API has changed since the one in the rendered document. I will update the RFC document once an API is agreed upon and a basic implementation is written for it.
For those curious of the current API, check my repo for the most current API and the WIP implementation.