-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Extract Stream methods into an IStream. #5749
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 do not think this is necessary. You can make the Print features private, hiding them from the user.
class MyStream : public Stream{ public: int available() { return 0; } //Fill in these as appropriate. void flush() { return; } int peek() { return -1; } int read() { return -1; } private: using Print::print; using Print::println; using Print::write; size_t write( uint8_t data ) { return (void)data, 0; } }; MyStream stream; void setup() { stream.read(); //Fine stream.println(); //Compile error } void loop() {}
flush()
is part of Stream, but you can also move it to the private section.
@Chris--A: That's a workaround, but not a good one:
void print_some_things(Print& p) { p.println("Hello world"); } MyStream stream; // using your definition void setup() { stream.read(); print_some_things(stream); // oops. This compiles just fine static_cast<Stream&>(stream).println("oops again"); Print* p = &stream; p->println("Oops"); }
The existence of an ineffective workaround is not sufficient justification for an improvement being unnecessary.
That isn't really an issue either. My workaround hides the print features when using the object directly, and for the cases that the object is cast to one of its inherited types, the print functionality has no effect.
A library shouldn't be left up to assumptions, if you don't support print features, then make it well known, or don't even mention it, then no one would have a reason to use them.
Another option using my original example is to make the Stream base private and only expose what you want:
class MyStream : private Stream{ public: int available() { return 0; } void flush() { return; } int peek() { return -1; } int read() { return -1; } using Stream::find; using Stream::findUntil; using Stream::parseInt; using Stream::readBytes; using Stream::readBytesUntil; private: size_t write( uint8_t data ) { return (void)data, 0; } }; MyStream stream; void setup() { stream.read(); //Fine stream.find('a'); //Fine Stream &s = stream; //Compile error Print &p = stream; //Compile error } void loop() {}
Similar to the above, you can also have a Stream reference or pointer as a member variable and only expose the input functions.
You've made the valid point that I've justified this poorly, so I've added some example code in my description.
A library shouldn't be left up to assumptions, if you don't support print features, then make it well known
That's kinda the point of this patch. There is currently no way to make it known that you support read features but not print features, yet there is a way to express the inverse. Why should things be this way?
What if I want to write a function that can read from Serial
and stream
? That seems perfectly sane, but your latest response doesn't allow that without templates.
Look at this another way - if IStream
did exist, can you think of a single reason it should be removed?
flush()
is part of Stream, but you can also move it to the private section.
Good catch, this probably doesn't belong in IStream
as I have it here, since it deals with output and not input
flush() is part of Stream, but you can also move it to the private section.
Also see #2387.
@matthijskooijman: Was tempted to fix that too. What's stopping that being merged?
@eric-wieser, Nothing that I can see, apart from maybe lack of developer time.
72c5c34
to
4d73331
Compare
Now that #2387 is merged, I've rebased this to be even simpler
4d73331
to
9df1c0a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the only line that actually changed in this file other than renaming Stream
to IStream
- it was previously class Stream : public Print
This allows streams to exist that are input-only, such as a keyboard.
9df1c0a
to
fe40b60
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nothing is left of the original file apart from the name Stream
, so this copyright notice has moved to IStream.h
CLAassistant
commented
Apr 9, 2021
CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.
Uh oh!
There was an error while loading. Please reload this page.
This allows streams to exist that are unidirectional.
A summary of this diff, which github does not show well:
Stream
toIStream
, adjusting comments in the same wayPrint
base class from the newIStream
Stream.h
withclass Stream : public Print, public IStream {}
I can't see any reason for this not to be backwards-compatible.
Example usage:
I'm open to other names here instead of
IStream
, such as:InputStream
Read
(to matchPrint
)Reader
(which avoids naming classes after verbs)