Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

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

Open
eric-wieser wants to merge 1 commit into arduino:master
base: master
Choose a base branch
Loading
from eric-wieser:split-stream

Conversation

Copy link
Contributor

@eric-wieser eric-wieser commented Dec 22, 2016
edited
Loading

This allows streams to exist that are unidirectional.

A summary of this diff, which github does not show well:

  • Rename the existing Stream to IStream, adjusting comments in the same way
  • Remove the Print base class from the new IStream
  • Add a brand new Stream.h with class Stream : public Print, public IStream {}

I can't see any reason for this not to be backwards-compatible.

Example usage:

class MyInputWithThisPatch : public IStream {
public:
 virtual int read() override { return ...; }
 virtual int peek() override { return ...; }
 virtual int available() override { return ...; }
 virtual void flush();
 // if this were : public Stream, we would have to override `write` as well
}
void write_base64_to(Print& print, int x) {
 // This was always possible
 print.write(...); // etc
}
int read_base64_from(IStream& stream) {
 // ^
 // But there was no good type to put here
 stream.read(...); // etc
}
void main() {
 MyInputWithThisPatch stream;
 int x = read_base64_from(stream); //ok
 int y = read_base64_from(Serial); //ok
 // this is a compiler error, as it should be. Without this patch, it would not be.
 // write_base64_to(stream, 1);
 write_base64_to(Serial, 1); // ok
}

I'm open to other names here instead of IStream, such as:

  • InputStream
  • Read (to match Print)
  • Reader (which avoids naming classes after verbs)

Copy link
Contributor

Chris--A commented Dec 28, 2016
edited
Loading

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.

Copy link
Contributor Author

eric-wieser commented Dec 28, 2016
edited
Loading

@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.

Copy link
Contributor

Chris--A commented Dec 28, 2016
edited
Loading

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.

Copy link
Contributor Author

eric-wieser commented Dec 28, 2016
edited
Loading

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?

Copy link
Contributor Author

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

Copy link
Collaborator

flush() is part of Stream, but you can also move it to the private section.

Also see #2387.

eric-wieser reacted with thumbs up emoji

Copy link
Contributor Author

@matthijskooijman: Was tempted to fix that too. What's stopping that being merged?

Copy link
Collaborator

@eric-wieser, Nothing that I can see, apart from maybe lack of developer time.

@facchinm facchinm added the Print and Stream class The Arduino core library's Print and Stream classes label Jan 20, 2017
Copy link
Contributor Author

eric-wieser commented Oct 11, 2017
edited by matthijskooijman
Loading

Now that #2387 is merged, I've rebased this to be even simpler


#define NO_IGNORE_CHAR '\x01' // a char not found in a valid ASCII numeric field

class IStream
Copy link
Contributor Author

@eric-wieser eric-wieser Oct 11, 2017

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.
@@ -1,6 +1,5 @@
/*
Stream.h - base class for character-based streams.
Copyright (c) 2010 David A. Mellis. All right reserved.
Copy link
Contributor Author

@eric-wieser eric-wieser Oct 11, 2017

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

Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Labels
Print and Stream class The Arduino core library's Print and Stream classes
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

AltStyle によって変換されたページ (->オリジナル) /