Arduino
Arduino copied to clipboard
Variadic print
Allows combining multiple arguments into a single call to Print::print[ln], like Serial.print("Answer=", 66, HEX). This feature requires C++11 or newer to work, but if it is not available the old calls can still be used. This change is backwards compatible: print(42, 16) prints "2A" as always, not "4216" (the latter can still be achieved with print(42, "", 16) ). Many functions from Print.cpp have been removed and replaced by inline versions in Print.h, most notably the println(...) ones. This results in a simplified (and thus easier to maintain) Print.cpp and slightly smaller executables.
Everything done, thanks for the feedback!
As requested via IRC, here's an example sketch for testing backwards compatibility: https://gist.github.com/cousteaulecommandant/3083c33cc83497d05e1fa12ae8cfaf17#file-example_backwards_compat-ino
As can be seen, the resulting size is slightly smaller with the new code. However, some examples show a huge improvement, such as this one, where using inlined functions implies creating only 3 functions and not 4: https://gist.github.com/cousteaulecommandant/3083c33cc83497d05e1fa12ae8cfaf17#file-example_println_inlining-ino On this other example, however, the resulting code is a few bytes larger, since it has to include several extra calls to println(void) that were formerly included in the previous call: https://gist.github.com/cousteaulecommandant/3083c33cc83497d05e1fa12ae8cfaf17#file-example_println_inlining_2-ino
Regarding documentation, the only feature that has been added is the variadic support (the other commits inside this PR are just optimizations or improvements on readability and maintainability), so there shouldn't be big changes in the documentation. In any case, the current documentation is still valid since these changes were designed to be backwards compatible.
@cousteaulecommandant, I finally got around to having another look at this. As we discussed on IRC, I'd like to see how feasible it is to extend this to also support custom formatters and/or more formatting options. As a proof-of-concept I made https://github.com/matthijskooijman/Arduino/commit/a3f0e33d946cc94e98f43f83accbe48b6ab14e93 today, which allows passing custom "formatter" objects after a value to format (e.g. instead of HEX). I've found that to reliably do this, I needed to move the actual printing code into a (non-variadic) doPrint() method, so print() can just take care of the variadic arguments (using some template magic in check_type, in a way similar to std::enable_if, to decide whether a second argument is a formatter or just something to print). As an added advantage, it seems it is no longer needed to repeat the list of int-as-second-argument-for-base-formatting as variadic versions). It might make sense to move this change into your PR if it really ends up being needed.
I'm still not sure how to add formatting options (e.g. options to default or other formatters) and especially how to combine these, so that needs a bit more thought.
Personally I don't think we should be putting too much effort into formatters for Print, since
Printis already quite complex,- something like
Serial.print(Format(number, digits, base, etc))would be easier to implement and understand, and (depending on how it's implemented) not only useful forPrintbut alsoStringand other uses, printf(#5938) might be a simpler solution for complex formatting (and if"%02X"is too scary for newbies, maybe a "printf formatter constructor class" could be developed).
In other words, if complex and extensible formatters end up being added, I'd go for functions that return a Printable or a String rather than arguments to Print::print, as they would be much easier to implement and document, and move the formatting problem somewhere else.
(Serial.print(number, HEX) et al would need to be kept for backwards compatibility, but I would avoid going in that direction for new formatting features.)