fortran-lang / stdlib

Fortran Standard Library
https://stdlib.fortran-lang.org
MIT License
1.06k stars 164 forks source link

Use to_string to format logicals as 0/1 #630

Open stigh opened 2 years ago

stigh commented 2 years ago

Motivation

By using to_string from stdlib_strings, it is now not possible to convert a logical to a string represented as an integer. In C languages it's normal to store a bool as an integer, ref: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/ginclude/stdbool.h.

Maybe the biggest motivation for this feature request is improved language interoperability when reading / writing files. Another motivation is that sometimes an integer can be refactored to a logical, for example if a variable was first defined as 3 choices, for example a door with the status of:

I suggest that following example is accepted, and printed as a padded integer, like so:

print *, to_string(.false., '(I5)')     !! "    0"

Example taken from here: https://stdlib.fortran-lang.org/page/specs/stdlib_strings.html#example_10

Prior Art

Here is an example that show C++ supports this kind of printing: https://en.cppreference.com/w/cpp/io/manip/boolalpha

This is an example from python3: print(f'{True:d} {False:d}') # prints "1 0"

Additional Information

No response

awvwgk commented 2 years ago

You could use merge:

use stdlib_strings, only : to_string
implicit none
logical :: bool
bool = .false.
print '(a)', to_string(merge(1, 0, bool), '(i5)')
end
stigh commented 2 years ago

Do you think it would be better if to_string solved it implicitly, like the Python example? Maybe this is nitpicking from my side.

awvwgk commented 2 years ago

Would be nice if we could solve this directly in to_string, however we first need a robust parser for format strings to know when to cast convert a logical into an integer.

Note that there is no requirement for logical values in Fortran to be represented as 1/0, therefore to_string(.true., '(i0)') would be compiler dependent unless we normalize it after detecting the IO transfer as integer.


use stdlib_strings, only : to_string
implicit none
logical :: bool
integer :: tmp

bool = .true.
print '(a)', to_string(transfer(bool, tmp), '(z8.8)')
bool = .false.
print '(a)', to_string(transfer(bool, tmp), '(z8.8)')
end

GFortran 11.1.0

00000001
00000000

Intel 2021.5.0

FFFFFFFF
00000000
arjenmarkus commented 2 years ago

You could support a limited form of format strings - after all: there is only a single value to be written, isn't there? A format like "(10(5x,i5))" is theorelically applicable but is it appropriate?

Op do 3 mrt. 2022 om 12:40 schreef Sebastian Ehlert < @.***>:

Would be nice if we could solve this directly in to_string, however we first need a robust parser for format strings to know when to cast a logical into an integer.

— Reply to this email directly, view it on GitHub https://github.com/fortran-lang/stdlib/issues/630#issuecomment-1057958304, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAN6YR46EM7DIPFWMU2BFCDU6CQL5ANCNFSM5P2A5ACQ . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub.

You are receiving this because you are subscribed to this thread.Message ID: @.***>

shahmoradi commented 2 years ago

I would follow the principle of Separation of Concerns in such use cases. Logical values are different from integers in Fortran. Having a procedure that coerces a logical to integer and then integer to character mixes two separate concerns. Perhaps a better way would be to convert the logical to integer first via another procedure and pass the result to to_string for conversion to string.