Why does `print` output a leading space?

The following program:

print *, "OK"
end

prints:

$ gfortran a.f90 && ./a.out 
 OK

Notice the leading space. What is the motivation behind this?

I found this link: fortran - How to remove leading space when printing with write? - Stack Overflow which says:

In list-directed format (the * in write(unit,*)) the compiler typically inserts a leading space. The first column used to be used to control line printers but that is now deleted from Fortran.

Wouldn’t it be more natural to change print *, "OK" to not print the leading space?

There could be a compiler option to control this behavior for backwards compatibility.

1 Like

Yes, that is Fortran folklore… :face_with_raised_eyebrow:

print '(A)', "OK"
does not print any leading space.

1 Like

I see, that is the phrase to google, thanks! Using it I found this thread from 1993 where @vsnyder wrote 30 years ago:

One of the reasons for what most perceive as “warts” in fortran 90 is
compatibility to fortran 77. The need for compatibility won’t go away:
there’s just too much software that uses each feature of fortran 77.
After 10-15 years, there will be too much software that uses each new
feature of fortran 90 to dream of removing any feature, or spelling it
differently (unless somebody makes a PD translator that re-writes fortran
77 and fortran 90 features in fortran '03). So carriage control is
probably here to stay, and any mistakes the committee made in formulating
fortran 90 are also here to stay.

@vmagnin yes, I use '(a)' if I want to suppress the leading space. But it seems quite a lot of typing when I just want to print a string.

I now understand the reasoning, so we’ll add an option to LFortran to make this configurable: Add a compiler option to make `print *, "ok"` print a leading space · Issue #1744 · lfortran/lfortran · GitHub.

2 Likes

For

print*,10, 20, 30

gfortran prints an initial space and 10 spaces between the numbers. g95 also prints an initial space but prints only 1 space between numbers. If possible, I would like the number of spaces between items in list-directed output to be configurable, or to at least have an option for compact output in the style of g95.

1 Like

@Beliavsky here is how it currently behaves:

program P
print*,10, 20, 30
end

This prints:

$ gfortran a.f90 && ./a.out
          10          20          30
$ lfortran a.f90           
10 20 30

I agree we have to make it configurable, I made an issue for it: Make default printing configurable using compiler options · Issue #1749 · lfortran/lfortran · GitHub.

Some notes about ASA (or ANSI, or FORTRAN) carriage control as it regards to FORTRAN (still part of COBOL last I knew as well) …

Spacing often depends on type and kind being printed

program main
use,intrinsic :: iso_fortran_env, only : int8, int16, int32, int64
write(*,*) 10_int8, 20_int8, 30_int8
write(*,*) 40_int8, 50_int8, 60_int8

write(*,*) 10_int16, 20_int16, 30_int16
write(*,*) 40_int16, 50_int16, 60_int16

write(*,*) 10_int32, 20_int32, 30_int32
write(*,*) 40_int32, 50_int32, 60_int32

write(*,*) 10_int16, 20_int64, 30_int64
write(*,*) 40_int16, 50_int64, 60_int64
end program main
   10   20   30   
   40   50   60
     10     20     30
     40     50     60
          10          20          30
          40          50          60
     10                   20                   30
     40                   50                   60

So it is usually (totally up to compiler) not just columns every 10 characters, it is because the default integer type needs that spacing to print from -(huge(0)) to huge(0).

Note the difference is primarily for creating neat columns; and so with several compilers the spacing depends on the type being printed, where the maximum required width for a type is the default. Several compilers use the same conventions (compact or column-aligned) for NAMELIST group output as well.

The G0 descriptor is very similiar to compact list-directed output

The G0 field (almost) lets you control it independent of the compiler, which has a lot of freedom in spacing, delimiters, and line length for list-directed I/O.

Some compilers still support the ANSI carriage control on stdout, including gfortran, as an option.

program main
character(len=*),parameter :: free='(*(g0,1x))'
print free, 10, 0.5, 1.0/3.0
end program main
10 0.500000000 0.333333343

with the caveat that complex values are printed as “(r,i)” in list-directed output, but as “r,i” using that format. So there is a relatively easy way to get the compact format in a portable fashion yourself, but the neat columns are harder to produce yourself generically with a format, so IMO the neat column format is a good default.

There is ASA carriage control support still out there

program main
character(len=*),parameter :: g='(*(g0,1x))'
!OPEN(unit=stdout,CARRIAGECONTROL='FORTRAN')                 ! cannot change
!OPEN(newunit=lun,file='/dev/tty',CARRIAGECONTROL='FORTRAN') ! does not work particularly well
OPEN(newunit=lun,file='test.asa',CARRIAGECONTROL='FORTRAN')
write(lun,g)'1new page'
write(lun,g)' stuff to print'
write(lun,g)' stuff to print'
write(lun,g)'+______________'
write(lun,g)' stuff to print'
end program main
gfortran main.f90 -o asa_test.exe -fdec
./asa_test.exe

I do not like the implementation much, as it is very quirky if mixed with list-directed I/O and cannot be used directly to the screen easily like the real DEC OpenVMS implementation and so on, but it is there.

I have a program that converts ASA files to Adobe PDF, and still get requests for it, albeit far less frequently than in the past, by the way. Since HTML really was not designed for page breaks, especially initially, some people are still looking for a really easy way to get a plain ASCII file that can be printed with page breaks at specified locations; particularly as less printers support control characters (let alone ASA carriage control, which at one time was ubiquitous).

2 Likes

In Abstracting Away the Machine, I read page 121:

PRINT acts like the PUNCH statement, but it directs the output to the line printer instead of to punched cards.

So, yes, punched cards seem not the culprit this time. :grin:

1 Like

There have been several discussions about this; found this one:

https://groups.google.com/g/comp.lang.fortran/c/VUP8j2_EOJU/m/r1jqskvKCgAJ

1 Like

There are two very different things being discussed in this thread.

For the leading space in list-directed output, that is indeed a remnant of Fortran carriage control, but it is still required by the standard:

Except for new records created by explicit formatting within a defined output procedure or by continuation of delimited character sequences, each output record begins with a blank character. (F2018 13.10.4)

As for spacing between numerical values in list-directed output, most older compilers simply supplied a fixed default width, for example, I12, leading to all those spaces. Now that Fortran has minimal-width output through G0, compilers could use that instead, and some do. Intel Fortran currently wants you to use its -standard-semantics option to get this, as users can and do complain when output changes appearance dramatically. That said, list-directed output leaves a lot up to the processor, so either behavior is acceptable.

6 Likes