RFC: Add `println(string $data = ''): int`

php.internals

tyson andre

5 years ago
Hi internals, I've created a new RFC https://wiki.php.net/rfc/println This proposes adding a global function to PHP to print a string followed by a unix newline (`\n`). Printing a string followed by a newline to stdout is a commonly performed operation in many applications and programming languages. Many programming languages provide a helper function to do this specifically, for readability and convenience. The choice of end of line string may differ, but many recent programming languages will unconditionally use the unix newline, to avoid unexpected differences in behavior between platforms. I've looked over prior related discussions such as https://externals.io/message/104545, and I've written down the reasons for my name choice and newline choice in the RFC. Any other feedback or elaboration on discussions? Thanks, - Tyson

Kamil Tekiela

5 years ago
Hi Tyson, I like this proposal, but why is the main argument optional? Wouldn't it make sense to always require a string as an argument? Regards, Kamil

tyson andre

5 years ago

Rowan Collins

5 years ago
On 13/03/2021 19:54, tyson andre wrote:
> I've created a new RFC https://wiki.php.net/rfc/println > This proposes adding a global function to PHP to > print a string followed by a unix newline (`\n`).
Hi Tyson, I'm on the fence on this one: I've certainly had occasions when it would be useful, but mostly in quick prototypes and demo code, and just as often in HTML context (where I'd want it to add '<br>') as plain text context. I am not keen, however, on the proposed implementation details, and would prefer it to much more closely match either print or echo. - Until reading this RFC, I would not have guessed that printf() returned the number of bytes written; I guess it's useful in C, where you're managing string buffers, but in PHP it feels very arbitrary. I would also not particularly associate this new function with printf() so my immediate guess would be the same return value as print (even though that return value, int(1), is equally arbitrary). - You explicitly state that this function would depend on strict_types mode, but echo and print do not. I can't see any particular advantage to doing so, and 'println((string)$foo)' would be longer than 'print $foo,"\n"' rather defeating the purpose. - Most importantly, I accept your points about a function being more forward- and backward-compatible, but worry that not making it a keyword will lead to further confusion about how parentheses interact with echo and print. There is a common misconception that they have some kind of "optional parentheses", because they are usually used with a single expression, so wrapping it in parentheses usually doesn't change the outcome; but this is not the case, and it does sometimes matter. As currently proposed, I can see people getting nasty surprises from these inconsistencies. For instance: print (1+2)*3; // prints "9" println (1+2)*3; // prints "3\n"; unless strict_types=1 is in effect, in which case TypeError print ($foo ?? 'Foo') . ($bar ?? 'Bar'); // prints "FooBar" if both vars are null println ($foo ?? 'Foo') . ($bar ?? 'Bar'); // never prints $bar or "Bar", because they are not passed to println() if ( something() && println($foo) && somethingElse() )  // does what it looks like, if println is a normal function if ( something() && print($foo) && somethingElse() )  // does not print $foo, because the expression passed is actually ($foo)&&somethingElse() Regards,
-- Rowan Tommins [IMSoP]

tyson andre

5 years ago
Hi Rowan, > Hi Tyson, > > I'm on the fence on this one: I've certainly had occasions when it would > be useful, but mostly in quick prototypes and demo code, and just as > often in HTML context (where I'd want it to add '<br>') as plain text > context. > > I am not keen, however, on the proposed implementation details, and > would prefer it to much more closely match either print or echo. > > > - Until reading this RFC, I would not have guessed that printf() > returned the number of bytes written; I guess it's useful in C, where > you're managing string buffers, but in PHP it feels very arbitrary. I > would also not particularly associate this new function with printf() so > my immediate guess would be the same return value as print (even though > that return value, int(1), is equally arbitrary). There's also the alias fputs of https://www.php.net/manual/en/function.fwrite.php which also returns the byte count. I'd considered just returning void, but then you'd have a mix of standard library functions that did/didn't return void and users would need to remember which did what. If someone actually had a need to use the result of println, it would likely be to count bytes, rather than to get a hardcoded constant such as 1/null. (or expression chaining, but `println('Starting') or die(2); // somehow failed to output` also has a use case) > - You explicitly state that this function would depend on strict_types > mode, but echo and print do not. I can't see any particular advantage to > doing so, and 'println((string)$foo)' would be longer than 'print > $foo,"\n"' rather defeating the purpose. I could change it to accept `mixed` and convert it to a string inside of the function. (or `object|string|float|int|bool|null` and throw or return false if an object could not be converted to a string). Throwing/warning for bool/null in strict mode may be worth it but may be more convenient to detect with external static analyzers) It initially seemed consistent with the behavior of https://www.php.net/fwrite to only accept a string and forcing callers to do so would catch unexpected edge cases with bool/null (''/'1'), floats, etc. in strict mode. Surprisingly, some output functions in PHP do accept `mixed`. https://www.php.net/file_put_contents accepts `mixed` and casts non-resources and non-arrays to strings (php-src/ext/standard/file.c) (handling of arrays/resources is different) ``` case IS_NULL: case IS_LONG: case IS_DOUBLE: case IS_FALSE: case IS_TRUE: convert_to_string(data); case IS_STRING: ``` Annoyingly, any decision I make would be inconsistent with something, e.g. file_put_contents currently doesn't even emit a notice for a failure to convert to string. ``` php > var_dump(file_put_contents('test.txt', new stdClass())); bool(false) ``` It definitely would be longer to use `println((string)$foo)`, but there may be cases where that would be done, e.g. if you are writing a script that would be reviewed/modified/used by programmers that are more familiar with languages that aren't PHP. (It'd be more readable using 1 output method than 3) There's also `println("$foo");` > - Most importantly, I accept your points about a function being more > forward- and backward-compatible, but worry that not making it a keyword > will lead to further confusion about how parentheses interact with echo > and print. There is a common misconception that they have some kind of > "optional parentheses", because they are usually used with a single > expression, so wrapping it in parentheses usually doesn't change the > outcome; but this is not the case, and it does sometimes matter. > > > As currently proposed, I can see people getting nasty surprises from > these inconsistencies. For instance: > > print (1+2)*3; // prints "9" > println (1+2)*3; // prints "3\n"; unless strict_types=1 is in effect, in > which case TypeError > print ($foo ?? 'Foo') . ($bar ?? 'Bar'); // prints "FooBar" if both vars > are null > println ($foo ?? 'Foo') . ($bar ?? 'Bar'); // never prints $bar or > "Bar", because they are not passed to println() Static analyzers for PHP such as Phan warn about the unused result of multiplication to catch cases like this, and other analyzers can easily add this check if they don't already check for it. https://github.com/phan/phan/wiki/Issue-Types-Caught-by-Phan#phannoopbinaryoperator > if ( something() && println($foo) && somethingElse() )  // does what it > looks like, if println is a normal function > if ( something() && print($foo) && somethingElse() )  // does not print > $foo, because the expression passed is actually ($foo)&&somethingElse() The fact that `print` doesn't require parenthesis is something that surprised me initially, though changing it to force it to use function syntax would be a much larger bc break more suitable for a major version, that I don't expect to pass. It may be possible to start deprecating `print` if the expression didn't contain a parenthesis (like the change in precedence of `+` and `-` did), but I'm not planning to work on that. (Python converted `print` from a statement in Python 2 to a call in Python 3) Regards, Tyson

Rowan Collins

5 years ago
On 14/03/2021 15:52, tyson andre wrote:
> There's also the alias fputs ofhttps://www.php.net/manual/en/function.fwrite.php > which also returns the byte count.
Notably, like printf(), that is borrowed directly from C, and probably dates from a time when most PHP programmers were also C programmers. That time is long past.
> Annoyingly, any decision I make would be inconsistent with something
I'm not sure why you're casting your net so wide. The name and use cases for this function put it squarely next to "print" and "echo" in my mind, and it would never occur to me to ask if it was consistent with most of the functions you've mentioned.
> It definitely would be longer to use `println((string)$foo)`, > but there may be cases where that would be done, > e.g. if you are writing a script that would be reviewed/modified/used by > programmers that are more familiar with languages that aren't PHP. > (It'd be more readable using 1 output method than 3)
Sorry, I'm not sure what you mean here. What 3 output methods are you talking about, and how does println((string)$foo) make a difference to them?
> There's also `println("$foo");`
Which is still marginally longer than the existing print "$foo\n";
> Static analyzers for PHP such as Phan warn about the unused result of multiplication > to catch cases like this, and other analyzers can easily add this check if they don't already check for it. > https://github.com/phan/phan/wiki/Issue-Types-Caught-by-Phan#phannoopbinaryoperator
That doesn't stop it being a nasty surprise. People will want to use "print" and "println" interchangeably, and making that difficult because they have different syntax is going to end up on lists of "things I hate about PHP", no matter how easily tools can spot it.
>> if ( something() && println($foo) && somethingElse() )  // does what it >> looks like, if println is a normal function >> if ( something() && print($foo) && somethingElse() )  // does not print >> $foo, because the expression passed is actually ($foo)&&somethingElse() > The fact that `print` doesn't require parenthesis is something that surprised me initially,
Just to be clear, it is not that print doesn't *require* parentheses, it's that print does not have parentheses, ever.
> though changing it to force it to use function syntax would be a much larger bc break > more suitable for a major version, that I don't expect to pass.
It hadn't even occurred to me to suggest that. I was suggesting the opposite: if we add something called "println", it should have identical syntax and behaviour to "print". The only difference should be the extra newline character in the output. Regards,
-- Rowan Tommins [IMSoP]

Unnamed Person

5 years ago
Hi, I have two questions regarding the RFC. 1. Why not provide an another optional attribute that allows to specify the end of line eliminator? 2. Why don't you configure Unix end of line in INI file? These additional steps will help users choose their favorite end of line for their projects. The INI settings should be INI_ALL, so libraries for various contexts can alter the attitude. For example, those who learn PHP in web browsers can use <BR>. Those who use it on shell will pick \r|\r\n|\n or simply \R. So, web server environments, such as XAMPP, can set <br> end of line eliminator in the INI file that they provide. Example: <?php ini_set('println.eol', EOL_UNIX); println('Hi PHP,'); println(); println('Regards'); ?> Besides, Let me give a strange circumstance that gives inappropriate result if Unix end of line is used on old windows machine. Observe the following lines written to shell. php test.php>test.txt&test.txt The contents of test.php file: <?php $content = file_get_contents(__FILE__); foreach (str_split($content) as $index => $char): printf("$index=$char\n"); endforeach; ?> Test.txt file will open in windows notepad. Here comes a bug that did not display Unix end of lines properly in old 7 machines and 8.1 machines. It was fixed in the recent tweaks to Notepad. Will PHP developers support only windows 10 and ignore the privious OSs? I also suggest creating end of line constants as integer's, so nobody could mistakenly write following: println('Hae, this is my test message.', ''); As for naming constants, I suggest using the following scheme: EOL_DEFAULT, EOL_PHP, EOL_CR, EOL_LF, EOL_CRLF, and EOL_HTML. Because there appeared an RFC that requested to Rename T_PAAMAYIM_NEKUDOTAYIM to T_DOUBLE_COLON. Why not fix this issue before it emerges? Additionally, multiple constants can be provided, too. EOL_UNIX and EOL_LF may have same value. The similar case applies to EOL_MAC and EOL_WINDOWS. Regards On 3/14/21, Rowan Tommins <rowan.collins@gmail.com> wrote:

Sara Golemon

5 years ago
On Sat, Mar 13, 2021 at 1:54 PM tyson andre <tysonandre775@hotmail.com> wrote:
> > I've created a new RFC https://wiki.php.net/rfc/println > This proposes adding a global function to PHP to > print a string followed by a unix newline (`\n`). > >
This isn't solving any problem that anyone is actually having. Yes, that includes you. You're not having this problem because it doesn't exist. We already have twice as many ways to output a string as any language needs and you want to add another because you'd rather type "LN" than "\N" ? Hard, negative ten thousand no on this. This is genuinely absurd. -Sara

Nikita Popov

5 years ago
On Mon, Mar 15, 2021 at 4:08 AM Sara Golemon <pollita@php.net> wrote:
> On Sat, Mar 13, 2021 at 1:54 PM tyson andre <tysonandre775@hotmail.com> > wrote: > > > > > I've created a new RFC https://wiki.php.net/rfc/println > > This proposes adding a global function to PHP to > > print a string followed by a unix newline (`\n`). > > > > > This isn't solving any problem that anyone is actually having. > Yes, that includes you. You're not having this problem because it doesn't > exist. > > We already have twice as many ways to output a string as any language needs > and you want to add another because you'd rather type "LN" than "\N" ? > Hard, negative ten thousand no on this. > This is genuinely absurd. >
My opinion matches Sara's, though maybe I wouldn't put it quite in those words ;) The difference between these two lines is one character: echo foo(), "\n"; println(foo()); I don't think this one character is worth adding another way to output strings, next to the two we already have (echo, print). Especially once you take into account the not entirely unambiguous semantics of printlln(). echo foo(), "\n" is entirely clear, and distinct from both echo foo(), PHP_EOL and echo foo(), "<br />\n". Regards, Nikita

Nikita Popov

5 years ago
On Mon, Mar 15, 2021 at 4:09 PM Nikita Popov <nikita.ppv@gmail.com> wrote:
> On Mon, Mar 15, 2021 at 4:08 AM Sara Golemon <pollita@php.net> wrote: > >> On Sat, Mar 13, 2021 at 1:54 PM tyson andre <tysonandre775@hotmail.com> >> wrote: >> >> > >> > I've created a new RFC https://wiki.php.net/rfc/println >> > This proposes adding a global function to PHP to >> > print a string followed by a unix newline (`\n`). >> > >> > >> This isn't solving any problem that anyone is actually having. >> Yes, that includes you. You're not having this problem because it doesn't >> exist. >> >> We already have twice as many ways to output a string as any language >> needs >> and you want to add another because you'd rather type "LN" than "\N" ? >> Hard, negative ten thousand no on this. >> This is genuinely absurd. >> > > My opinion matches Sara's, though maybe I wouldn't put it quite in those > words ;) > > The difference between these two lines is one character: > > echo foo(), "\n"; > println(foo()); > > I don't think this one character is worth adding another way to output > strings, next to the two we already have (echo, print). Especially once you > take into account the not entirely unambiguous semantics of printlln(). > echo foo(), "\n" is entirely clear, and distinct from both echo foo(), > PHP_EOL and echo foo(), "<br />\n". >
Apparently I am incapable of counting in the absence of a monospace font. The difference is actually two characters, but I think the point still stands... And in some cases it will actually be the other way around, because echo "foo\n"; is two characters shorter than println("foo");. Nikita