Repository: j3-fortran/fortran_proposals
Branch: master
Commit: 3732db5150dc
Files: 26
Total size: 155.8 KB
Directory structure:
gitextract_o6bns626/
├── CODE_OF_CONDUCT.md
├── README.md
├── augmented_assignment/
│ └── augmented_assignment.txt
├── proposal-template.txt
└── proposals/
├── assert/
│ └── design_by_contract.txt
├── c23_interop/
│ ├── 26-112.txt
│ └── 26-122.txt
├── cmplx-real-pointers.txt
├── conditional_expressions/
│ └── 21-165.txt
├── default_optional_arguments/
│ └── proposal.txt
├── fp_interop/
│ ├── 25-189r1.txt
│ ├── 25-203.txt
│ └── 25-203r1.txt
├── namelist_delimiters/
│ └── namelist_proposal.txt
├── namespace_modules/
│ ├── 19-246.txt
│ └── 20-108.txt
├── protected_attribute.txt
├── run-time_polymorphism/
│ ├── Examples/
│ │ ├── AppendixA/
│ │ │ └── taylor.f90
│ │ ├── AppendixB/
│ │ │ ├── taylor.f90
│ │ │ ├── taylor.java
│ │ │ └── taylor.rs
│ │ └── Text/
│ │ └── taylor_basic.f90
│ ├── Fortran_OOP.bib
│ └── Fortran_OOP.tex
├── traits/
│ └── 20-109.txt
└── worklist/
└── 26-116-din3a-recommend.txt
================================================
FILE CONTENTS
================================================
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to make participation in our project and
our community a harassment-free experience for everyone, regardless of age,
body size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual
identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account or acting as an appointed
representative at an online or offline event. Representation of a project may
be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing or otherwise unacceptable behavior may be
reported by contacting one of the project maintainers at ondrej@certik.us or
zjibben@lanl.gov. All complaints will be reviewed and investigated and will
result in a response that is deemed necessary and appropriate to the
circumstances. The project team is obligated to maintain confidentiality with
regard to the reporter of an incident. Further details of specific enforcement
policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [https://contributor-covenant.org/version/1/4][version]
[homepage]: https://contributor-covenant.org
[version]: https://contributor-covenant.org/version/1/4/
================================================
FILE: README.md
================================================
# Fortran Proposals
This repository contains proposals for the Fortran Standard Committee in the [Issues](https://github.com/j3-fortran/fortran_proposals/issues) section. The idea for this repository is to act as a public facing discussion tool to collaborate with the user community to gather proposals for the Fortran language and systematically track all discussions for each proposal.
## Workflow
1. Open a new issue with a new addition that you would like to see eventually included in the Fortran standard.
2. The issue gets discussed.
3. Start drafting a formal proposal to be submitted into [Documents](https://j3-fortran.org/doc/meeting) for the US committee. One has to find an advocate at the committee to advocate for the proposal.
4. If the draft proposal receives negative feedback from the committee, then we will close the issue and we will have documented reasons why the idea got rejected. One can open a new issue, reference the closed issue and advocate why it should be revisited.
5. Getting the proposal through the Committee is a long process, with multiple approvals, formal requirements, specifications, edits to the standard, etc. We will document this step in more detail. During this process, we can document the latest status at the issue.
### Proposal Format
Proposals should be text files, using [proposal-template.txt](proposal-template.txt) as a template. The reference line is optional, and is used reference previous J3 papers (e.g. 12-345r6, not a full link). The top line should not be modified--the XX-XXX is automatically modified when uploaded. Proposals are limited to 75 characters per line, and are generally around 50 - 350 lines of text. Proposals benefit from minimal code examples and use cases. While J3 will accept PDF proposals, such detailed documents are usually be better suited as a reference, so the proposal itself can be concise.
## Plan For This Repository
Currently this repository is maintained by
[Ondřej Čertík](https://github.com/certik),
[Zach Jibben](https://github.com/zjibben) and
[Gary Klimowicz](https://github.com/gklimowicz)
(all members of the Fortran Committee). We plan to maintain this repository,
keep it up to date with what the committee is doing and use it to collaborate
on ideas and proposals with the Fortran community.
## Code of Conduct
Please note that all participants of this project are expected to follow our
Code of Conduct. By participating in this project you agree to abide by its
terms. See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md).
## Links
* [US Fortran Standards Committee](https://j3-fortran.org/)
* [International Fortran Standard Committee](https://wg5-fortran.org/)
================================================
FILE: augmented_assignment/augmented_assignment.txt
================================================
To: J3 J3/XX-XXX
From: Leonard Reuter
Subject: Augmented Assignment Operators
Date: 2022-July-11
Proposal for Fortran Standard: 202y
1. Introduction
The proposal is to introduce augmented assignment operators. Example:
i +.= 1
Here, `i` is incremented by 1.
In the same manner, the operators `-.=`, `*.=`, `/.=`, `**.=` are proposed
to be defined as well as the operator `.op.=` for a user-defined operator
`.op.`.
The intrinsic interpretation of e.g. '+.=' can not be overridden but should
always call 'operator(+)' and 'assignment(=)'.
This proposal originated at the J3 GitHub repository at [1]. The proposed
syntax originated from a comment by Reinhold Bader in the J3 mail list [2].
2. Motivation
Augmented assignment operators improve the readability of code in making
immediately clear to the reader, that the new value of the variable
depends on the old one.
Furthermore, if a function is called during the evaluation of the
left-hand side, the augmented assignment operators show, that this
function is only called once:
real :: A(n)
...
A(get_index()) +.= x
If the above example were to be written without augmented assigment, how
often `get_index` is called would depend on the compiler.
The dot is added between the operator and `=`, since `/=` is already in
use as an alias to the '.ne.' relational operator.
3. Discussing Objections
3.1. Conflict with '/=' [4]
This is circumvented by introducing the dot, i.e. '/.='
3.2. The compiler can optimize 'a = a + b*c' better than 'a +.= b*c' [5]
"What happens to 'a += b * c' is often optimized to an FMA if the compiler
flags or defaults allow ISO/IEEE violation" [6].
3.3. Instead of augmented assignment, an additional symbol can be
introduced to replace the LHS [7,8]
If this symbol were '.LHS.', it would allow for further simplification:
real :: a
...
a = LOG(a)
could be replaced with
real :: a
...
a = LOG(.LHS.)
While discussing this may prove worthwhile, it lacks the intuitivity of
simple augmented assignment and should be discussed independent of it.
3.4 Cognitive load [9]
Most programmers are used to augmented assignment from other languages,
it is more cognitive load to remember, that this is not possible in
Fortran than to actually use it.
4. References
[1] https://github.com/j3-fortran/fortran_proposals/issues/113
[2] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013261.html
[3] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013251.html
[4] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013254.html
[5] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013262.html
[6] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013279.html
[7] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013287.html
[8] https://wg5-fortran.org/N1951-N2000/N1972.pdf
[9] https://mailman.j3-fortran.org/pipermail/j3/2021-August/013277.html
================================================
FILE: proposal-template.txt
================================================
To: J3 J3/XX-XXX
From:
Subject:
Date:
#Reference:
================================================
FILE: proposals/assert/design_by_contract.txt
================================================
To: J3 J3/XX-XXX
From: William B. Clodius
Subject: Facilitate design by contract
Date: August 1, 2020
#Reference: 04-142.txt, 04-143.txt, 04-144.txt, 04-212.txt,
04-219.txt, 04-376.txt, 04-414.txt
Proposal for Fortran Standard: 202y (NOT 202x)
1. Introduction
This paper contains a proposal to allow programmers to use "Design by
Contract". Inspired by languages such as C++, Java, and Ada, Fortran
is considering incorporating exception handling into the language. In
contrast, C++'s standard committees have decided that its users have
been overusing exception handling, and has been seeking to incorporate
other, simpler, error handing systems.[1] One approach, that has been
incorporated into C++ 2020, is design by contract.[2,3] I believe
Fortran would benefit by incorporating design by contract into the
language, at a cost much less than would be incurred by incorporating
exception handling.
Design by contract (DbC) is intended to address programmer errors and
only those errors. The idea is to specify: first the logical
preconditions the inputs to a procedure are required to satisfy for
its correct operation; second, the conditions the code is asserted to
satisfy at various stages of its logic if the code logic is correct,
and finally, the post-conditions the code ensures it will satisfy if
the pre-conditions are met. To implement these checks, C++ 2020 has
defined the attributes: expects, assert, and ensures,
respectively. During the debugging phase of development these serve to
detect when the conditions are not satisfied, stop processing when
they are not satisfied, and report errors in a consistent format. In
code deployment the expects attribute documents the pre-conditions the
calling code must satisfy, and the ensures attribute documents the
post-conditions the calling code can expect will be satisfied,
providing a "contract" between the calling code and the
callee. Normally the processor provides flags such that the logical
tests can be active during testing, and inactive on deployment.
DbC can be met with a minimum of one new statement, for testing
anywhere in the code body, say ASSERT, but ideally there would be
three new statements: one the equivalent of ASSERT, one to be used at
the start of the procedure to test pre-conditions, say REQUIRE, and
one to be used immediately before the procedure's return to test
post-conditions, say ENSURE. All three statements would be simple in
form and have simple semantics.
2. Problem
Currently a programmer typically tests for user errors using one of:
1. Hardcoding the tests for errors using IF or SELECT CASE blocks;
2. Writing the equivalent of an ASSERT subroutine: or
3. Writing the equivalent of an ASSERT macro.
The first is the most natural for single checks, but requires care to
give a consistent response to the user, and adds an overhead in
deployment unless commented or edited out. The second allows a
consistent response to the user, but has a larger overhead than the
first, that can only be removed by being commented or edited out. The
third allows a consistent response to the user that can be clearer
about the problem location, and can have zero overhead on deployment
with appropriate pre-processor flags, but does require a dependence
on a preprocessor. None document for the user the pre and post
conditions the user can expect for properly working code.
3. Use cases
A simple function that requires non-negative integer arguments.
REAL FUNCTION FACTORIAL( n )
INTEGER, INTENT(IN) :: N
INTEGER :: I
REQUIRE( N >= 0 )
FACTORIAL = 1
DO I=1, N
FACTORIAL = FACTORIAL * I
END DO
ENSURE (FACTORIAL >= N )
RETURN
END FUNCTION FACTORIAL
A simple subroutine that swaps targets.
SUBROUTINE TARGET_SWAP( A, B )
TYPE(EXAMPLE), POINTER, INTENT(INOUT) :: A, B
TYPE(EXAMPLE), POINTER :: C
REQUIRE( ASSOCIATED(A) ) ! Requires pointer status of A be
! defined
REQUIRE( ASSOCIATED(B) ) ! Requires pointer status of B be
! defined
C => A
A => B
B => C
ENSURE( ASSOCIATED(A) )
ENSURE( ASSOCIATED(B) )
RETURN
END SUBROUTINE TARGET_SWAP
A procedure that requires one optional argument to be present if the
other optional argument is present.
SUBROUTINE OPTIONALS( A, B )
TYPE(EXAMPLE), OPTIONAL, INTENT(IN) :: A, B
REQUIRE( PRESENT(A) .EQV. PRESENT(B) )
...
RETURN
END SUBROUTINE OPTIONALS
A test of a problematic procedure call
SUBROUTINE PROBLEM_CALL ( ..., A, ... )
...
TYPE(EXAMPLE), POINTER :: A
...
CALL PROBLEM( A )
ASSERT( ASSOCIATED( A ) )
...
RETURN
END SUBROUTINE PROBLEM_CALL
4. Prior art
The term design by contract as applied to programming languages has
its origins in the language Eiffel.[4,5] Since then, in addition to
C++ it has been adopted by Ada,[6] D,[7] and Fortress. The C standard
library comes with the assert macro so C can be said to partially
support DbC. To our knowledge no Fortran compiler has implemented
anything to support DbC. Many users implement their own equivalent of
an ASSERT subroutine or macro so there is some demand for these
capabilities.
5. Specification
All three statements will have similar behavior. All three will take
as their arguments a list of scalar logical expressions, that if all
.TRUE. does nothing, and if one is .FALSE. writes output to the
ERROR_UNIT of ISO_FORTRAN_ENV and stops as if ERROR STOP was
invoked. The writes will all indicate the location of the executed
statement: either the procedure name with the name of the enclosing
module, or the name of the file including the statement and the line
number of the statement, or both. All three will write out the text of
the logical expression that failed, with a prefix. The prefix will
differ between the three statements. Example prefixes for the REQUIRE
statement is "PRE-CONDITION FAILED: ", for the ASSERT statement is
"ASSERTION FAILED: ". and for the ENSURE statement is "POST-CONDITION
FAILED: ".
The semantics of all three statements are similar. They all should
respond the same to compiler flags that invoke different behavior in
development versus in deployment. In development, they each perform a
logical test with the .FALSE. branch writing to ERROR_UNIT, and then
stopping with an stop code, and the other branch a null operation
that continues processing. In deployment they are as if they were
commented out. These semantics are similar to a logical test with one
branch invoking ERROR STOP and the other branch continuing
processing. They should have restrictions similar to those of ERROR
STOP, being allowed in PURE procedures, but not in ELEMENTAL
procedures.
4. Syntactic options
The syntax for the statements depend on whether they should be
considered executable statements, and should go in the executable
part, or attributes of the sub-programs, and should go in the
specification part. It is difficult to think of ASSERT as any thing
other than an executable statement. For ASSERT I think the following
syntax is appropriate
assert-stmt is ASSERT( assertion-list )
where
assertion is logical-expr
REQUIRE and ENSURE can be thought of as either sub-program attributes
or executable statements. If treated as sub-program attributes then
the syntax could be something like
requires-stmt is REQUIRES :: requires-expr-list
ensures-stmt is ENSURES :: ensures-expr-list
requires-expr is logical-expr
ensures-expr is logical-expr
Constraint: requires-expr shall be a restricted expression.
If thought of as run time expressions then the appropriate syntax may
be
require-stmt is REQUIRE( require-expr-list )
ensure-stmt is ENSURE( ensure-expr-list )
In all of the syntactical forms each item in the effective
logical-expr-list shall be tested in sequence, and a error message
will be generated for the first item in the list that tests as
.FALSE. that shows the logical expression that failed the test.
5. Backward compatibility
The three proposed statements do not match statements implemented by
any processor that I am aware of, and so their addition should not
change the meaning of any directly supported application. It is
likely, however, that some users already have an ASSERT macro, that
approximates the ASSERT statement's semantics. I suspect they will
welcome the new ASSERT, but cannot be certain. This problem could be
minimized by using a name other than ASSERT, say CHECK.
6. Impact on the standard
My guess is that describing each statement will take about half a page
of main text, plus a half page note describing for all three
statements the semantics of a quality of implementation, plus a few
sentences to describe changes from the previous standard and define
terms. Maybe three pages total.
References
[1] Herb Sutter, "Zero-overhead deterministic exceptions: Throwing
values",
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf
[2] G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers,
and B. Stroustrup, "A Contract Design"
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0380r1.pdf
[3] G. Dos Reis, J. D. Garcia, J. Lakos, A. Meredith, N. Myers, and
B. Stroustrup, "Support for contract based programming in C++"
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0542r5.html
[4] B. Meyer, "Eiffel: The Language," Prentice Hall, second printing,
1992.
[5] B. Meyer, "Applying 'Design by Contract'," in Computer (IEEE) 25,
pp. 40-51, Oct. 1992.
http://se.ethz.ch/~meyer/publications/computer/contract.pdf
[6] R. Dewar, "Ada 2012: Ada with Contracts", Dr. Dobb's, Apr. 9,
2013. https://www.drdobbs.com/architecture-and-design/ada-2012-ada-with-contracts/240150569
[7] W. Bright, "D Programming Language, Contract Programming", Digital
Mars. https://dlang.org/spec/contracts.html
================================================
FILE: proposals/c23_interop/26-112.txt
================================================
To: J3 J3/26-112
From: Patrick Fasano
Subject: Edits for updating references from C17 to C23
Date: 2026-January-14
References:
ISO/IEC 9899:2024 Programming languages -- C ("C23")
25-203r1 US05: Edits for C interchange and extended floating types
ISO/IEC 9899:2018 Programming languages -- C ("C17")
25-007r1 Fortran 2028 Working Draft
1 Background
============
The ISO C23 specification (ISO/IEC 9899:2024) is the latest revision of
the standard for the C language. At meeting #238 in January 2026, J3
passed paper 25-203r1 with edits to add support to Fortran 202Y for
interoperability with new floating-point types added in C23. As such,
25-203r1 introduced references to the C23 specification.
This paper provides edits to update and replace references to the ISO
C17 specification (ISO/IEC 9899:2018) with references to the ISO C23
specification (ISO/IEC 9899:2024). The edits in this paper complement
those presented in 25-203r1 for work item US05.
2 Edits (relative to 25-007r1)
==============================
[2:6] Replace the line:
ISO/IEC 9899:2018, Programming languages -- C
with the line
ISO/IEC 9899:2024, Programming languages -- C
Note to editor: This edit is the same as that in 25-203r1.
------------------------------------------------------------------------
[7:22] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
------------------------------------------------------------------------
[50:36] Replace
ISO/IEC 9899:2018, 5.1.2.2.3 and 7.22.4.4
with
ISO/IEC 9899:2024, 5.2.2.3.4 and 7.24.5.4
------------------------------------------------------------------------
[50:39] Replace
ISO/IEC 9899:2018, 7.22.4.4
with
ISO/IEC 9899:2024, 7.24.5.4
------------------------------------------------------------------------
[57:note] In the first paragraph, replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
and in the second paragraph, replace
ISO/IEC 9899:2018, 6.7.6.3
with
ISO/IEC 9899:2024, 6.7.7.4
------------------------------------------------------------------------
[102:27] Replace
ISO/IEC 9899:2018, 6.7.2.2
with
ISO/IEC 9899:2024, 6.7.3.3
------------------------------------------------------------------------
[103:note 2] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
and replace
ISO/IEC 9899:2018, 6.7.2.2
with
ISO/IEC 9899:2024, 6.7.3.3
Note to J3/editor: ISO/IEC 9899:2024 does not actually guarantee that
enumeration constants fit in a C int. This will be addressed by
rewriting or removing this Note in a forthcoming edit paper.
------------------------------------------------------------------------
[103:note 3] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
------------------------------------------------------------------------
[115:note] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
and replace
ISO/IEC 9899:2018, 6.4.3
with
ISO/IEC 9899:2024, 6.4.4
------------------------------------------------------------------------
[252:19] Replace
ISO/IEC 9899:2018, 7.21.2
with
ISO/IEC 9899:2024, 7.23.2
------------------------------------------------------------------------
[538:4] Replace
ISO/IEC 9899:2018, 6.7.6.3
with
ISO/IEC 9899:2024, 6.7.7.4
------------------------------------------------------------------------
[538:8] Replace
ISO/IEC 9899:2018, 6.2.2
with
ISO/IEC 9899:2024, 6.2.2
------------------------------------------------------------------------
[538:30] Replace two instances of:
(_Bool)
with:
(bool)
Note to editor: This edit is the same as that in 25-203r1.
------------------------------------------------------------------------
[539:23] Replace
ISO/IEC 9899:2018, 5.2.1 and 5.2.2
with
ISO/IEC 9899:2024, 5.3.1 and 5.3.3
------------------------------------------------------------------------
[540:16-17] Replace
ISO/IEC 9899:2018, 6.3.2.3 and 6.5.9
with
ISO/IEC 9899:2024, 6.3.3.3 and 6.5.10
------------------------------------------------------------------------
[543:note] Replace
ISO/IEC 9899:2018, 6.2.5
with
ISO/IEC 9899:2024, 6.2.5
------------------------------------------------------------------------
[545:26] Replace
ISO/IEC 9899:2018, 6.5.3.2
with
ISO/IEC 9899:2024, 6.5.4.3
------------------------------------------------------------------------
[546:note] Replace
ISO/IEC 9899:2018, 6.5.3.2
with
ISO/IEC 9899:2024, 6.5.4.3
------------------------------------------------------------------------
[546:10] Replace
ISO/IEC 9899:2018, 6.5.3.4
with
ISO/IEC 9899:2024, 6.5.4.5
------------------------------------------------------------------------
[547:13] Replace the line
The C types mentioned in Table 18.2 are defined in ISO/IEC
9899:2018, 6.2.5, 7.19, and 7.20.1.
with the line
The C types mentioned in Table 18.2 are defined in ISO/IEC
9899:2024, 6.2.5, 7.21, 7.22, and H.2.
Note to editor: This edit is corrected relative to the one that appears
in 25-203r1.
------------------------------------------------------------------------
[548:table 18.2] Replace the following:
_Bool
with:
bool
Note to editor: This edit is the same as that in 25-203r1.
------------------------------------------------------------------------
[548:note] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
------------------------------------------------------------------------
[548:note 1] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
------------------------------------------------------------------------
[549:note 4] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
and replace
ISO/IEC 9899:2018, 6.2.7
with
ISO/IEC 9899:2024, 6.2.7
------------------------------------------------------------------------
[551:16-17] Delete
(ISO/IEC 9899:2018, 6.2.5, 7.19, and 7.20.1)
[551:note 1] After "The referenced type of a C pointer type", insert:
(ISO/IEC 9899:2024, 6.2.5)
such that the note reads:
<<NOTE 1>>
The <<referenced type>> of a C pointer type (ISO/IEC 9899:2024,
6.2.5) is the C type of the object that the C pointer type points
to. For example, the referenced type of the pointer type
\texttt{int *} is \texttt{int}.
------------------------------------------------------------------------
[551:note 2] Replace
ISO/IEC 9899:2018, 7.16
with
ISO/IEC 9899:2024, 7.16
------------------------------------------------------------------------
[557:table 18.4] Replace the following:
+---------------+-------+
| CFI_type_Bool | _Bool |
+---------------+-------+
with:
+---------------+------+
| CFI_type_Bool | bool |
| CFI_type_bool | bool |
+---------------+------+
Note to editor: This edit is the same as that in 25-203r1.
------------------------------------------------------------------------
[561:8-9] Replace
ISO/IEC 9899:2018, 3.2
with
ISO/IEC 9899:2024, 3.2
------------------------------------------------------------------------
[564:18-19] Replace
ISO/IEC 9899:2018, 3.2
with
ISO/IEC 9899:2024, 3.2
------------------------------------------------------------------------
[566:26] Replace
ISO/IEC 9899:2018, 3.4.3
with
ISO/IEC 9899:2024, 3.5.3
------------------------------------------------------------------------
[566:31-32] Replace
ISO/IEC 9899:2018, 6.2.4
with
ISO/IEC 9899:2024, 6.2.4
------------------------------------------------------------------------
[568:20] Replace
ISO/IEC 9899:2018, 6.2.2
with
ISO/IEC 9899:2024, 6.2.2
------------------------------------------------------------------------
[568:23] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
------------------------------------------------------------------------
[569:4] Replace
ISO/IEC 9899:2018, 7.13
with
ISO/IEC 9899:2024, 7.13
------------------------------------------------------------------------
[569:7] Replace
ISO/IEC 9899:2018, 7.14.1
with
ISO/IEC 9899:2024, 7.14.1
------------------------------------------------------------------------
[569:note] Replace
ISO/IEC 9899:2018
with
ISO/IEC 9899:2024
------------------------------------------------------------------------
[569:25] Replace
ISO/IEC 9899:2018, 7.14.1
with
ISO/IEC 9899:2024, 7.14.1
===END===
================================================
FILE: proposals/c23_interop/26-122.txt
================================================
To: J3 J3/26-122
From: Patrick Fasano & HPC
Subject: Reqs/specs for interoperability with C23 enumerations
Date: 2026-February-23
Reference: ISO/IEC-9899:2018 ! Programming languages -- C ("C17")
Reference: ISO/IEC-9899:2024 ! Programming languages -- C ("C23")
Reference: WG5/N2212 ! The new features of Fortran 2023
Reference: WG14/N3029 ! Improved Normal Enumerations
Reference: WG14/N3030 ! Enhanced Enumerations
Reference: 24-007 ! Fortran 2023
Reference: 26-112 ! Edits for updating references from C17 to C23
1 Background
============
bg01. The ISO C23 specification (ISO/IEC 9899:2024) introduced changes
to enumerations that create an incompatibility with the current
specification of Fortran interoperable enumerations and enum
types. Specifically, WG14 adopted two proposals affecting
enumerations in C23:
* N3029: "Improved Normal Enumerations", which allows enumeration
values greater than INT_MAX and smaller than INT_MIN.
* N3030: "Enhanced Enumerations", which allows specifying an
underlying type for enumerations.
bg02. WG14/N3029 "Improved Normal Enumerations" changes the rules for
the types of enumeration constants and the underlying type of the
enumeration. In C17, all enumeration constants were required to be
representable as an int. In C23, enumeration constants may have
values that are not representable as an int; the compiler
determines an underlying integer type that can represent all the
values defined in the enumeration.
bg03. WG14/N3030 "Enhanced Enumerations" adds the ability to specify the
underlying type of an enumeration. In C17, the underlying type of
an enumeration was implementation-defined (subject to being able
to represent all the values). In C23, the underlying type can be
explicitly specified in the enum declaration (e.g., `enum x : long
long { ... }`).
bg04. The current Fortran specification (24-007, subclause 7.6.1)
relies on the assumption that C enumeration constants fit within a
C int. This assumption is explicitly stated in Note 2 of the
subclause: "ISO/IEC 9899:2018 guarantees the enumeration constants
fit in a C int (ISO/IEC 9899:2018, 6.7.2.2). Therefore, the
Fortran processor can evaluate all enumerator values using the
integer type with kind parameter C_INT, and then determine the
kind parameter of the integer type that is interoperable with the
corresponding C enumerated type." With the adoption of WG14/N3029
in C23, this guarantee no longer holds. C enumerations may now
have values that cannot be represented in a C int.
bg06. The edits in paper 26-112 adopted by J3 at meeting #238 in January
2026 replaced references to C17 with C23 in the Fortran
specification. That introduced a factually incorrect statement
regarding C enumerations in Note 2 of subclause 7.6.1, which was
not addressed in that paper. This paper addresses this issue by
proposing options for resolving the incompatibility and providing
specifications for each option.
2 Requirements
==============
rq01. The Fortran standard should be updated to address the
incompatibility between Fortran interoperable enumerations and C23
enumerations.
3 Straw polls
=============
Straw poll
----------
How should the incompatibility with C23 enumerations be resolved?
OPTION A: Restrict interoperability to C enums compatible with C_INT.
Add a precondition that says interoperability requires that
the C enum have a type that fits within an INTEGER(C_INT).
OPTION B: Implicitly determine KIND via new C23 rules.
Remove the incorrect note and implicitly require that the
Fortran processor determine the KIND of the enumerators via
the new C23 rules; do not allow explicitly declaring the KIND.
Optionally, add a new note on how the Fortran processor
evaluates the enumerator values to determine the interoperable
KIND parameter.
OPTION C: Implicitly determine KIND via new C23 rules and add explicit
KIND parameter to ENUM.
Require that the Fortran processor
determine the KIND of the enumerators via the new C23 rules;
add an explicit (optional) KIND parameter to ENUM declarations
which override any implicit determination.
The subgroup recommends OPTION A.
Straw poll analysis
-------------------
PROS OPTION A:
AP01. Minimizes expected implementation burden: no syntax change, no
runtime change.
AP02. Implicitly fixes the problem with Note 2 (making it true by
restriction, after some minor rephrasing).
AP03. Should not require any Fortran compiler backend changes, just
spec wording.
CONS OPTION A:
AC01. Does not allow interoperability with C's new "wider" (64-bit)
enum types, or even explicitly "narrower" enum types (e.g. 8-bit).
AC02. Must add spec constraint to restrict allowable enumerators.
AC03. Compiler changes to check the new constraint are required.
PROS OPTION B:
BP01. No syntax change.
BP02. Maintains interoperability with the implicit behavior of C enums.
BP03. No normative standard changes required.
BP04. Compatible with C paper WG14/N3029.
CONS OPTION B:
BC01. Likely requires some compiler changes to accommodate new
wider enums.
BC02. Does not provide full interoperability with all C enums, because
it cannot express all enums that are possible in C23 (specifically
those with specified underlying types defined in WG14/N3030).
PROS OPTION C:
CP01. Maintains full interoperability with all C enums.
CONS OPTION C:
CC01. Requires introducing new syntax.
CC02. Requires compiler parsing and backend changes (hence might be
considered a new feature).
4 Specifications
================
4.1 Specifications for Option A
-------------------------------
sa01. The definition of "interoperable enumerator" should be constrained
to require the values of the enumerators be representable in the
integer type with kind parameter C_INT.
sa02. Update or remove Note 2 in subclause 7.6.1 to reflect that
interoperability is restricted to enumerations where constants fit
in a C int.
4.2 Specifications for Option B
-------------------------------
sb01. Remove Note 2 in subclause 7.6.1 which incorrectly states that C
enumeration constants are guaranteed to fit in a C int.
sb02. The Fortran processor shall determine the interoperable kind of
the enumerators based on the type chosen by the companion
processor for the corresponding C enumerated type, which may be
wider than C_INT.
sb03. Optionally, add a replacement Note to subclause 7.6.1 to explain
that C23 allows enumeration constants that do not fit in a C int,
and that the Fortran processor may need to evaluate all enumerator
values using an integer type with wider range than the integer
type with kind parameter C_INT, before determining the kind
parameter that is interoperable with the C enumerated type.
4.3 Specifications for Option C
-------------------------------
sc01. Extend the syntax of the ENUM statement to allow an optional KIND
parameter to specify the underlying integer type. One possible
syntax (shown only for illustrative purposes):
ENUM[(KIND=scalar-int-constant-expr)], BIND(C) [:: enum-type-name]
Thus, for a C23 enumerator declared as this:
enum my_long_enum : long {
red = 4,
blue = 9,
yellow
};
a corresponding Fortran interoperable enumeration could be
declared as:
ENUM(KIND=C_LONG), BIND(C) :: my_long_enum
ENUMERATOR :: RED = 4, BLUE = 9
ENUMERATOR YELLOW
END ENUM
sc02. If the KIND parameter is present, the kind type parameter of the
enumerators is the value specified by the KIND parameter. The
corresponding interoperable C enumerated type is one that uses a
compatible underlying type (in addition to the other requirements
specified in 24-007, sec 7.6.1 para 2).
sc03. If the KIND parameter is absent, the Fortran processor shall
determine the interoperable kind of the enumerators based on the
type chosen by the companion processor for the corresponding C
enumerated type, which may be wider than C_INT.
sc04. Add a Note to subclause 7.6.1 to explain that C23 allows
enumeration constants that do not fit in a C int, and that the
Fortran processor may need to evaluate all enumerator values using
an integer type with wider range than the integer type with kind
parameter C_INT, before determining the kind parameter that is
interoperable with the C enumerated type.
==END==
================================================
FILE: proposals/cmplx-real-pointers.txt
================================================
To: J3 J3/24-129
From: Pierre Hugonnet
Subject: allow complex pointer to reals and vice versa
Date: 2024-June-10
#Reference:
1. Introduction
The proposal is to allow a complex pointer to be associated to a real
array, and similarly to allow a real pointer to be associated to a
complex scalar or array.
2. Motivation
In short, the motivation is to save memory and cpu-memory bandwidth
in some HPC contexts, typically when dealing with very large or huge
data volumes.
When working in the Fourier domain, it is common to use in-place real
to complex Fourier transforms. Before the forward transform one
generally stores data in a real array, and the transform outputs
complex numbers in the same real array, with interleaved real and
imaginary parts. Once in the Fourier domain the complex type is more
appropriate to perform computations, but this requires either:
- duplicating the data into a complex array after the transform,
thus cancelling the advantage of the in-place transform. Note that in
HPC, and particularly when dealing with large data volumes,
duplicating the data is really something that we want to avoid
whenever possible.
- or using various non-standard tricks that rely on the fact that
virtually all compilers store a complex number by the sequence
real part / imaginary part.
For instance, consider a code that performs a FFT based convolution
at some point:
program foo
real, allocatable :: r1(:), r2(:), r3(:)
integer, parameter :: n = 100000
! ...
allocate( r1(n), r2(n), r3(n) )
! ... some computations on r1(:) and r2(:) as reals
call rfft(r1) ; call rfft(r2)
call fftconvol(r1,r2,r3,n/2) ! called without any interface,
! hence type mismatchs
call irfft(r3)
! ... some computations on r3(:) as real
end program
! dangling routine (not contained and not in a module)
subroutine fftconvol(c1,c2,c3,n)
integer, intent(in) :: n
complex, intent(in) :: c1(n), c2(n)
complex, intent(out) :: c3(n)
c3(:) = c1(:) * c2(:)
end subroutine
With modern Fortran another trick has got quite popular, by using the
C interoperability features. Nonetheless the trick is non standard:
program foo
use iso_c_binding
real, allocatable :: r1(:), r2(:), r3(:)
integer, parameter :: n = 100000
complex, pointer :: c1(:), c2(:), c3(:)
! ...
allocate( r1(n), r2(n), r3(n) )
! ... some computations on r1(:) and r2(:) as reals
call rfft(r1) ; call rfft(r2)
! non-standard trick
call c_f_pointer( c_loc(r1), c1, [n/2] )
call c_f_pointer( c_loc(r2), c2, [n/2] )
call c_f_pointer( c_loc(r3), c3, [n/2] )
c3(:) = c1(:) * c2(:)
call irfft(r3)
! ... some computations on r3(:) as real
end program
The `c_f_pointer()` trick is even mentioned in the official
documentation of FFTW, which is one of the most popular FFT
library [1].
More generally, this is a recurrent topic on forums or on
StackOverflow [2]
3. Proposed solution
The proposal essentially aims at standardizing the usual practice
above, by allowing a real array to be viewed as a complex array and
vice-versa. The above code would become:
program foo
real, allocatable, target :: r1(:), r2(:), r3(:)
integer, parameter :: n = 100000
complex, pointer :: c1(:), c2(:), c3(:)
! ...
allocate( r1(n), r2(n), r3(n) )
! ... some computations on r1(:) and r2(:) as reals
call rfft(r1) ; call rfft(r2)
c1 => r1 ; c2 => r2 ; c3 => r3
c3(:) = c1(:) * c2(:)
call irfft(r3)
! ... some computations on r3(:) as real
end program
3.1. Syntax
No new syntax need to be created, the usual pointer association can be
used, with additional rules and restrictions:
`c => r`
- `r` shall be a *contiguous* real array, which has either the target
or the pointer attribute
- `c` shall be a complex array pointer of the same kind as `r`, and of
the same rank by default (but pointer rank remapping can be used)
- `c` could also be a complex scalar pointer, in the case r is a
rank-1 array of size 2
- the size of the first dimension of `r` shall be even
- `c%re` shall refer to the same storage as `r(1::2)` (rank-1), or
`r(1::2,:)` (rank-2), etc...
- `c%im` shall refer to the same storage as `r(2::2)` (rank-1), or
`r(2::2,:)` (rank-2), etc...
`r => c`
- the exact opposite
- `c` shall be a *contiguous* complex array or a complex scalar, which
has either the target or the pointer attribute
- `r` shall be a real array pointer of the same kind as `c`, and of the
same rank by default (but pointer rank remapping can be used)
- if `c` is a scalar, then `r` shall be a rank-1 pointer of size 2
- same other rules as above
3.2 Alternative syntaxes
If one wants to make the association between two different types more
explicit and more type-safe, a new syntax may be introduced:
Alternative syntax 1 (kind of pointer casting):
```
c => complex :: r
r => real :: c
```
Alternative syntax 2:
```
c => complex_pointer(r)
r => real_pointer(c)
```
Alternative syntax 3 (similar to the c_f_pointer() subroutine):
```
call complex_pointer(r,c[,shape][,lower])
call real_pointer(c,r[,shape][,lower])
```
Alternative syntax 4 (more generic, in case other inter-type
associations would be allowed in future versions of the standard):
```
call storage_associate(r,c[,shape][,lower])
call storage_associate(r,c[,shape][,lower])
```
3.3 Intermediate representation
During the discussions it has been proposed tu use an intermediate
representation between the real and complex view, which would be a real
view with an augmented rank and first dimension of size 2. Instead of
going directly from `r(n)` to `c(n/2)` one would define by rank
remapping:
`r2(1:2,1:n/2) => r(1:n)`, then `c => r2`
And the other way:
`r2 => c`, then `r(1:n) => r2(1:2,1:n/2)`
This could also be coupled with a new pseudo-component notation `c%reim`
that would be equivalent the `r2` respresentation (i.e. `c%reim` would be
`real`, with a shape [2,n/2]).
I personally find that such an intermediate representation just makes
the proposal more complex than it needs to be, and that nothing really
useful can be performed with it. Moreover the `c%reim` notation would
require another change in the standard to allow non zero ranks on both
sides of `%`.
3.4 Prototyping, etc...
I think that this proposal doesn't need to have a preliminary prototype
implementation, as it essentially consists in standardizing an already
existing and common practice. A prototype implementation would do
nothing else than mimicing the `c_f_pointer()` trick.
4. Issues / Objections / Limitations
4.1. Memory layout
This proposal would constraint the memory layout of the complex type
beyond what the current standard does. However, the required layout
seems to be the de-facto standard, used by virtually all existing
compilers (i.e. storing a complex scalar by the sequence real part/
imaginary part, in that order).
Also, the proposal would not prevent alternative memory layouts for
the arrays in future versions of the standard, such as the row major
storage. For instance, in the case of a row major 2D array, `c%re`
would refer to the same storage as `r(:,1::2)` instead of `r(1::2,:)`
for the column major case. More generally the obtained view would be
layout dependent, and the standard would have to describe the view for
each layout.
Similarly, the proposal would be compatible with the so-called
split-complex layout, if introduced later (without assessing here if
such a layout is possible at all). In this layout, a complex array is
stored with all the real parts first, then all the imaginary parts.
In this case, `c%re` would refer to the same storage as `r(1:n/2)`.
4.2. Argument association
Allowing a real actual argument to be associated to a complex dummy
argument -and vice-versa- has also been considered, but it would raise
backward compatibility issues. So this part has been dropped from the
proposal.
4.3. Alignment
Considering for instance a default real type stored on 4 bytes, the
default complex type is stored on 8 bytes. Compilers may prefer/want to
align the complex arrays on 8 bytes boundaries, which cannot be
guaranteed if a complex pointer is associated to an arbitrary real array
(e.g. `c => r(2:)`). If this is a problem, the pointer association may
be allowed only the other way (real pointer associated to a complex
array), where alignement should not be a problem.
5. References
[1] https://www.fftw.org/fftw3_doc/Reversing-array-dimensions.html
[2]
https://fortran-lang.discourse.group/t/
implicit-real-complex-conversion-in-fortran/7381
https://stackoverflow.com/questions/31590004/
is-the-storage-of-complex-in-fortran-guaranteed-to-be-two-reals
https://stackoverflow.com/questions/36977737/
pass-a-real-array-if-a-complex-array-is-expected
Discussions related to this proposal:
https://fortran-lang.discourse.group/t/complex-type-storage-again/7020
https://github.com/j3-fortran/fortran_proposals/issues/323
https://github.com/j3-fortran/fortran_proposals/pull/325
================================================
FILE: proposals/conditional_expressions/21-165.txt
================================================
To: J3 J3/21-165
From: Ondrej Certik, Milan Curcic, Zach Jibben
Subject: Conditional expressions using intrinsic function
Date: 2021-June-27
Reference: 21-157, 21-159
Paper 21-157 proposes two syntactic forms for conditional expressions. The
paper 21-159 proposes an alternative form. This paper proposes to implement
conditional expressions using an intrinsic function.
The syntactic forms in 21-157 are too verbose, as argued in 21-159. The
form in 21-159 is concise, but based on the poll [1], it is not the most
popular either.
We propose the following syntactic form
<cond-expr> is ifthen( predicate, consequent, alternative )
where the `predicate` is a scalar logical expression and the `consequent`
and `alternative` are compatible expressions. The `alternative` can be
another `ifthen` as shown in an example below.
Examples:
res = ifthen(x >= 0.0, sqrt(x), -0.0)
res = ifthen(present(x), a, ifthen(present(b), b, 0))
Objections raised in the past:
1) It is harder to do chaining due to the extra parenthesis at the end.
Answer: it seems in practice it is not too bad, as in the second example
above. Here is a longer chain:
res = ifthen(present(x), x, ifthen(present(y), y,
ifthen(present(z), z, 0)))
2) `ifthen` does not behave like a regular function, it is effectively new
syntax, so we might as well actually introduce new syntax, to make it less
confusing
There is a precedent in optional arguments, where the argument is not
evaluated but passed through through nested functions until it hits the
function `present`. In a similar way, the arguments to `ifthen` are not
evaluated ahead of time, but rather passed into the function `ifthen`
itself, similar to how `present(x)` works. Both `ifthen` and `present` must
be implemented by the compiler itself, they cannot be implemented in
standard Fortran code.
References:
[1] https://fortran-lang.discourse.group/t/
poll-fortran-202x-conditional-expressions-syntax/1425
================================================
FILE: proposals/default_optional_arguments/proposal.txt
================================================
To: J3 J3/XX-XXX
From: Milan Curcic, Jeremie Vandenplas, Zach Jibben
Subject: Default value for optional arguments
Date: 2020-January-10
Reference: 18-136r1, 18-122r1
1. Introduction
This paper contains a proposal for Fortran 202y, to allow a programmer
to specify a default value for optional dummy arguments. This would
allow the programmer to then safely reference such variables in
expressions regardless of whether the actual argument is present or
not.
2. Problem
Currently, standard Fortran does not allow setting a default value for
optional arguments. Default value of an optional argument is the value
that the dummy argument would take if the corresponding actual argument
is not present. If declaring a dummy argument as optional, the user
must:
* Explicitly test for the presence of the actual argument using the
intrinsic function present();
* Use a separate variable inside the procedure to assign the value
because the optional dummy argument that is not present must not be
referenced in expressions other than as actual argument to the
intrinsic function present().
This example function illustrates the problem:
real function quadratic(x, a, b, c)
! returns a + b * x + c * x**2 if c is present
! and a + b * x otherwise
real, intent(in) :: x, a, b
real, intent(in), optional :: c
real :: c_tmp ! use another var. to reference the missing arg
c_tmp = 0 ! default value if c is not present
if (present(c)) c_tmp = c
quadratic = a + b * x + c_tmp * x**2
end function quadratic
For any dummy argument with the optional attribute, the programmer must
use the intrinsic function present() to check for the presence of the
argument. Furthermore, if the optional dummy argument is meant to be
used in multiple places in the procedure, the programmer is likely to
use the pattern from the example above, where a "temporary" variable is
declared and used in place of the dummy argument, which disconnects the
implementation from the user interface. Furthermore, this requires at
least 3 lines of code (declaration of c_tmp, initialization of c_tmp,
and testing for the presence of c) only to handle the scenario of a
missing optional argument.
This proposal seeks to address the issue that explicitly checking for
presence of the optional dummy argument and using a helper variable is
cumbersome and error-prone. The primary benefit of this feature is the
reduction in source code needed to handle optional arguments. This
benefit is even greater in scenarios where the optional argument is
used in many places in the procedure, and a helper variable is used for
its value instead. Reduction in needed source code would result in more
readable and more correct programs. The secondary benefit of this is
programmer happiness, as working with optional arguments would require
less typing.
3. Proposed solution
As suggested by Van Snyder in 18-136r1, the problem could be solved by
allowing an optional argument to be initialized using a constant
expression. The optional argument would then only be initialized if the
corresponding actual argument is not provided by the caller. Example:
real function quadratic(x, a, b, c)
! returns a + b * x + c * x**2 if c is present
! and a + b * x otherwise
real, intent(in) :: x, a, b
real, intent(in), optional :: c = 0
quadratic = a + b * x + c * x**2
end function quadratic
In this snippet, we use the assignment operator (=) to specify the
default value of the optional dummy argument.
Like initializer, the optional argument can be assigned any constant
expression, as defined in Section 10.1.12 of 18-007r1.
While there may be concerns that the same syntax is used to implicitly
set the save attribute for variables in procedures, there is no
conflict because the language prohibits dummy arguments from having an
initializer, or the save attribute. The change to the standard to allow
this feature would thus be to allow an optional dummy argument to have
an initializer, which would be triggered only when corresponding actual
argument is not passed by the caller.
This improvement has already been suggested by Van Snyder in 18-136r1,
has received votes in the user survey for 202X (see
isotc.iso.org/livelink/livelink?func=ll&objId=19530634&objAction=Open),
and appeared on Data subgroup's wishlist at meeting 215 (see 18-122r1).
4. Backward compatibility
This addition to the language would not break any existing standard
conforming Fortran program, and thus preserves Fortran's backward
compatibility.
5. Related behavior
5.1. present()
There are two possible behaviors of the function present() when an
initializer is provided.
The first behavior would be that the function present() always returns
.true. when the optional dummy argument has an initializer, and
independently of the fact that an actual argument is passed or not
by the caller. Therefore, with such a behavior, the function present()
becomes useless for optional arguments with a default value.
Example:
real function foo(a, b)
real, intent(in), optional :: a
real, intent(in), optional :: b = 0
print*, present(a) !.true. if an actual argument is provided
!by the caller, .false. otherwise
print*, present(b) !always .true. due to the initializer
end function foo
The second behavior would be that the function present() returns
.true. or .false. when an actual argument is passed or not by the
caller, and independently of the fact that the optional dummy
argument has, or hasn't an initializer.
A use case of this behavior of the function present() could be:
real function foo(a, b)
real, intent(in) :: a
real, intent(in), optional :: b = 1.234
if (present(b)) then
... !expensive input validation here
end if
...
end function foo
5.2. intent(out)
There are several different possible behaviors for intent(out)
variables. One option is to disallow default values on optional
intent(out) variables. However, there are use cases where it is
desirable to return the value of a variable if a caller requests it,
without requiring the added logic of present() and "temporary"
variables described above.
Alternatively, we might treat intent(in) and intent(out) variables
identically, so that the following would be valid:
real function foo(a)
real, intent(out), optional :: a = 0
end function foo
The benefit is that, just like proposed for intent(in) variables,
intent(out) variables would be usable regardless of whether the value
is actually passed back to the caller, removing the need for present()
and "temporary" variables. The complication is that a present
intent(out) variable is initially undefined, meaning the logic of
present() might still be necessary in this case. Furthermore, the
behavior suggested above where present() = .true. always for variables
with a specified default would not be desired for intent(out)
variables. A possible use case for this behavior could be:
integer function open(filename, mode, iostat) result(u)
character(*), intent(in) :: filename
character(*), intent(in), optional :: mode
integer, intent(out), optional :: iostat = 0
character(3) :: mode_
character(:),allocatable :: action_, position_, status_, access_
character(:),allocatable :: form_
!some code
!....
open(newunit=u, file=filename, &
action = action_, position = position_, status = status_, &
access = access_, form = form_, &
iostat = iostat)
end function
A third option is that optional intent(out) variables with a specified
default are always initialized to that default, even when present,
rather than leaving them undefined.
5.3 intent(inout)
Dummy arguments with intent(inout) or no specified intent follow from
the behavior for intent(in) and intent(out). If an optional
intent(inout) variable is present, the existing behavior is
followed. The dummy variable has the value of the actual argument on
invocation of the procedure, its data may be used or manipulated during
the scope of the procedure, then it is returned to the scoping unit. If
an actual argument is not provided for an optional dummy argument with
a specified default and intent(inout), the variable recieves the
default value and may be used or modified throughout the procedure. The
data is then not returned to the scoping unit, since no actual argument
was provided.
This would allow the following routine:
subroutine foo(x)
integer, intent(inout), optional :: x = 0
! do stuff that could use or assign to x
end subroutine foo
This would be equivalent to:
subroutine foo(x)
integer, intent(inout), optional :: x
integer :: x_
if (present(x)) then
x_ = x
else
x_ = 0
end if
! do stuff that could use or assign to x_
if (present(x)) x = x_
end subroutine foo
5.4 Arrays
Default values for array dummy arguments present a difficulty,
particularly expressions involving a scalar. Some decision must be made
for the behavior in the following instances:
real, intent(in), optional :: a(:) = 0
real, intent(inout), optional :: b(:) = 0
real, intent(inout), allocatable, optional :: c(:) = 0
In each case, the size of the array is not determined if an actual
argument is not provided. One option is of course to forbid defaults
for arrays. This isn't preferable, but allowing defaults for scalars
only may still address the majority of use cases. Another option is to
forbid array broadcasting as a default specifier. That is, allow only
defaults such as [0,0] for arrays, where the length is clear.
6. Further discussion
Online discussion that led to this proposal can be found at
https://github.com/j3-fortran/fortran_proposals/issue/22.
================================================
FILE: proposals/fp_interop/25-189r1.txt
================================================
To: J3 J3/25-189r1
From: Patrick Fasano
Subject: Requirements and specifications for interoperability with C
interchange and extended types
Date: 2025-October-28
References:
ISO/IEC 9899:2024 Programming languages -- C ("C23")
(working draft N3220)
WG5/N2249 Fortran 202Y Work Items
23-176 Add extended floating-point types defined in ISO C23
to ISO_C_BINDING
ISO/IEC 60559:2020 Floating-Point arithmetic
IEEE 754-2019 IEEE Standard for Floating-Point Arithmetic
25-189 Requirements and specifications for interoperability with C
interchange and extended types
1 Background
============
bg01. The ISO C23 specification (ISO/IEC 9899:2024) added support for
interchange and extended floating-point types (C23 Annex H). The
current Fortran 202Y work list WG5/N2249 includes adding
interoperability with these types as accepted work item US05. At
meeting #230 in June 2023, J3 accepted paper 23-176 as
background/use-case for additional interchange types.
bg03. This paper contains formal requirements and specifications for
Fortran 202Y proposal US05, "Add extended floating-point types
defined in ISO C23 to ISO_C_BINDING".
bg05. The C23 standard adds a large number of new types, importing
significant portions of ISO/IEC 60559 (a.k.a IEEE 754) into its
specification. During discussion of 25-189 at meeting #237, a
straw poll of J3 indicated strong consensus for adding support for
extended binary floating types (rq07-rq09) and decimal floating
types (rq11), but strong consensus against extended decimal
floating types (25-189 rq13) and arbitrary-size floating types
(25-189 rq15-rq17). This revision amends the paper to reflect this
consensus.
2 Requirements
==============
rq02. The ISO_C_BINDING module shall provide integer named constants
for KIND parameters corresponding to the C interchange floating
types '_Float16', '_Float32', '_Float64', and '_Float128'.
rq03. If the companion processor defines '__STDC_IEC_60559_BFP__' and
'__STDC_IEC_60559_TYPES__', then the KIND parameters corresponding
to '_Float32' and '_Float64' shall equal those corresponding to
'float' and 'double', respectively.
rq05. The ISO_C_BINDING module shall provide integer named constants
for KIND parameters corresponding to the C interchange complex
types '_Float16_Complex', '_Float32_Complex', '_Float64_Complex',
and '_Float128_Complex'. The values of the named constants shall
equal those of the respective constants for the interchange
floating types.
rq07. The ISO_C_BINDING module shall provide integer named constants
for KIND parameters corresponding to the C extended floating types
'_Float32x', '_Float64x', and '_Float128x'.
rq09. The ISO_C_BINDING module shall provide integer named constants
for KIND parameters corresponding to the C extended complex types
'_Float32x_Complex', '_Float64x_Complex', and
'_Float128x_Complex'. The values of the named constants shall
match those of the respective constants for the extended floating
types.
rq11. The ISO_C_BINDING module shall provide integer named constants
for KIND parameters corresponding to the C interchange decimal
floating types '_Decimal32', '_Decimal64', and '_Decimal128'.
3 Specifications
================
sp01. For all integer named constants to be added to the ISO_C_BINDING
module, the value shall be a valid real kind type parameter or
shall be -1 if the companion processor's type does not have a
precision equal to the precision of any of the Fortran processor's
real kinds, -2 if the companion processor's type does not have a
range equal to the range of any of the Fortran processor's real
kinds, -3 if the companion processor's type has neither the
precision nor range of any of the Fortran processor's real kinds,
-4 if there is no interoperating Fortran processor kind for other
reasons, and -5 if the companion processor does not define the
corresponding C type.
sp02. To the ISO_C_BINDING module, add the following integer named
constants for real KIND parameters:
+----------------+--------------------+
| Named constant | C interchange type |
+----------------+--------------------+
| C_FLOAT16 | _Float16 |
| C_FLOAT32 | _Float32 |
| C_FLOAT64 | _Float64 |
| C_FLOAT128 | _Float128 |
+----------------+--------------------+
If the companion processor defines '__STDC_IEC_60559_BFP__' and
'__STDC_IEC_60559_TYPES__', then the constants 'C_FLOAT32' and
'C_FLOAT64' shall have the same values as 'C_FLOAT' and
'C_DOUBLE', respectively (C2023 H.2.4.2).
sp05. To the ISO_C_BINDING module, add the following integer named
constants for real KIND parameters:
+--------------------+--------------------+
| Named constant | C interchange type |
+--------------------+--------------------+
| C_FLOAT16_COMPLEX | _Float16_Complex |
| C_FLOAT32_COMPLEX | _Float32_Complex |
| C_FLOAT64_COMPLEX | _Float64_Complex |
| C_FLOAT128_COMPLEX | _Float128_Complex |
+--------------------+--------------------+
The values of each of these named constants shall be the same as
the respective constants defined in sp01.
sp07. To the ISO_C_BINDING module, add the following integer named
constants for real KIND parameters:
+----------------+-----------------+
| Named constant | C extended type |
+----------------+-----------------+
| C_FLOAT32X | _Float32x |
| C_FLOAT64X | _Float64x |
| C_FLOAT128X | _Float128x |
+----------------+-----------------+
sp09. To the ISO_C_BINDING module, add the following integer named
constants for real KIND parameters:
+---------------------+--------------------+
| Named constant | C extended type |
+---------------------+--------------------+
| C_FLOAT32X_COMPLEX | _Float32x_Complex |
| C_FLOAT64X_COMPLEX | _Float64x_Complex |
| C_FLOAT128X_COMPLEX | _Float128x_Complex |
+---------------------+--------------------+
sp11. To the ISO_C_BINDING module, add the following integer named
constants for real KIND parameters:
+----------------+--------------------+
| Named constant | C interchange type |
+----------------+--------------------+
| C_DECIMAL32 | _Decimal32 |
| C_DECIMAL64 | _Decimal64 |
| C_DECIMAL128 | _Decimal128 |
+----------------+--------------------+
=== END ===
================================================
FILE: proposals/fp_interop/25-203.txt
================================================
To: J3 J3/25-203
From: Patrick Fasano
Subject: US05: Edits for C interchange and extended floating types
Date: 2025-October-30
References:
ISO/IEC 9899:2024 Programming languages -- C ("C23")
(working draft N3220)
WG5/N2249 Fortran 202Y Work Items
ISO/IEC 60559:2020 Floating-Point arithmetic
25-189r1 Requirements and specifications for interoperability with
C interchange and extended types
25-007r1 Fortran 2028 Working Draft
1 Background
============
The ISO C23 specification (ISO/IEC 9899:2024) added support for
interchange and extended floating-point types (C23 Annex H). The current
Fortran 202Y work list WG5/N2249 includes adding interoperability with
these types as accepted work item US05. At meeting #237 in October 2025,
J3 passed paper 25-189r1 as requirements and specifications for
additional floating types.
This paper provides edits for Fortran 202Y proposal US05, "Add C
interoperability for new interchange floating point types in C".
The ISO C23 specification also added 'bool' as a keyword with an
alternate spelling of '_Bool'. This paper optionally provides edits for
Fortran 202Y to propagate this change.
2 Edits (relative to 25-007r1)
==============================
------------------------------------------------------------------------
[xv] Add to "Intrinsic modules" the sentences:
Named constants have been added to the ISO_C_BINDING module to allow
interoperability with C interchange and extended floating-point formats
defined in ISO/IEC 9899:2024 Annex H.
------------------------------------------------------------------------
[539:7-14] Replace 18.2.2 paragraph 4 with the following paragraphs:
The values of C_FLOAT, C_DOUBLE, C_LONG_DOUBLE, C_FLOAT16, C_FLOAT32,
C_FLOAT64, C_FLOAT128, C_FLOAT32X, C_FLOAT64X, C_FLOAT128X, C_DECIMAL32
C_DECIMAL64, and C_DECIMAL128 shall each be a valid value for a real
kind type parameter on the processor or shall be -1 if the companion
processor's type does not have a precision equal to the precision of any
of the Fortran processor's real kinds, -2 if the companion processor's
type does not have a range equal to the range of any of the Fortran
processor's real kinds, -3 if the companion processor's type has neither
the precision nor range of any of the Fortran processor's real kinds, -4
if there is no interoperating Fortran processor kind for other reasons,
or -5 if the companion processor does not define the corresponding C
type. The values of C_FLOAT_COMPLEX, C_DOUBLE_COMPLEX,
C_LONG_DOUBLE_COMPLEX, C_FLOAT16_COMPLEX, C_FLOAT32_COMPLEX,
C_FLOAT64_COMPLEX, C_FLOAT128_COMPLEX, C_FLOAT32X_COMPLEX,
C_FLOAT64X_COMPLEX, and C_FLOAT128X_COMPLEX shall be the same as those
of C_FLOAT, C_DOUBLE, C_LONG_DOUBLE, C_FLOAT16, C_FLOAT32, C_FLOAT64,
C_FLOAT128, C_FLOAT32X, C_FLOAT64X, and C_FLOAT128X, respectively. If
the companion processor defines the C preprocessor macros
__STDC_IEC_60559_BFP__ and __STDC_IEC_60559_TYPES__, the values of
C_FLOAT32 and C_FLOAT64 shall be the same as those of C_FLOAT and
C_DOUBLE, respectively.
------------------------------------------------------------------------
[2:6] Insert a new line:
ISO/IEC 9899:2024, Programming languages -- C
------------------------------------------------------------------------
[547:13] Replace the line
The C types mentioned in Table 18.2 are defined in ISO/IEC
9899:2018, 6.2.5, 7.19, and 7.20.1.
with the line
The C types mentioned in Table 18.2 are defined in ISO/IEC
9899:2024, 6.2.5, 7.22, and H.2.
------------------------------------------------------------------------
[547:table 18.2] Add the following rows to the REAL section of the table:
+--------------+-------------+
| C_FLOAT16 | _Float16 |
| C_FLOAT32 | _Float32 |
| C_FLOAT64 | _Float64 |
| C_FLOAT128 | _Float128 |
| C_FLOAT32X | _Float32x |
| C_FLOAT64X | _Float64x |
| C_FLOAT128X | _Float128x |
| C_DECIMAL32 | _Decimal32 |
| C_DECIMAL64 | _Decimal64 |
| C_DECIMAL128 | _Decimal128 |
+--------------+-------------+
------------------------------------------------------------------------
[547-548:table 18.2] Add the following rows to the COMPLEX section of
the table:
+---------------------+---------------------+
| C_FLOAT16_COMPLEX | _Float16 _Complex |
| C_FLOAT32_COMPLEX | _Float32 _Complex |
| C_FLOAT64_COMPLEX | _Float64 _Complex |
| C_FLOAT128_COMPLEX | _Float128 _Complex |
| C_FLOAT32X_COMPLEX | _Float32x _Complex |
| C_FLOAT64X_COMPLEX | _Float64x _Complex |
| C_FLOAT128X_COMPLEX | _Float128x _Complex |
+---------------------+---------------------+
------------------------------------------------------------------------
[557:table 18.4] Add the following rows after the row for
CFI_type_long_double:
+---------------------+-------------+
| CFI_type_Float16 | _Float16 |
| CFI_type_Float32 | _Float32 |
| CFI_type_Float64 | _Float64 |
| CFI_type_Float128 | _Float128 |
| CFI_type_Float32x | _Float32x |
| CFI_type_Float64x | _Float64x |
| CFI_type_Float128x | _Float128x |
| CFI_type_Decimal32 | _Decimal32 |
| CFI_type_Decimal64 | _Decimal64 |
| CFI_type_Decimal128 | _Decimal128 |
+---------------------+-------------+
------------------------------------------------------------------------
[557:table 18.4] Add the following rows after the row for
CFI_type_long_double_Complex:
+----------------------------+---------------------+
| CFI_type_Float16_Complex | _Float16 _Complex |
| CFI_type_Float32_Complex | _Float32 _Complex |
| CFI_type_Float64_Complex | _Float64 _Complex |
| CFI_type_Float128_Complex | _Float128 _Complex |
| CFI_type_Float32X_Complex | _Float32x _Complex |
| CFI_type_Float64X_Complex | _Float64x _Complex |
| CFI_type_Float128X_Complex | _Float128x _Complex |
+----------------------------+---------------------+
------------------------------------------------------------------------
[538:30] Replace two instances of:
(_Bool)
with:
(bool)
------------------------------------------------------------------------
[548:table 18.2] Replace the following:
_Bool
with:
bool
------------------------------------------------------------------------
[557:table 18.4] Replace the following:
+---------------+-------+
| CFI_type_Bool | _Bool |
+---------------+-------+
with:
+---------------+------+
| CFI_type_Bool | bool |
| CFI_type_bool | bool |
+---------------+------+
------------------------------------------------------------------------
===END===
================================================
FILE: proposals/fp_interop/25-203r1.txt
================================================
To: J3 J3/25-203r1
From: Patrick Fasano
Subject: US05: Edits for C interchange and extended floating types
Date: 2026-January-12
References:
ISO/IEC 9899:2024 Programming languages -- C ("C23")
(working draft N3220)
WG5/N2249 Fortran 202Y Work Items
ISO/IEC 60559:2020 Floating-Point arithmetic
25-189r1 Requirements and specifications for interoperability with
C interchange and extended types
25-007r1 Fortran 2028 Working Draft
1 Background
============
The ISO C23 specification (ISO/IEC 9899:2024) added support for
interchange and extended floating-point types (C23 Annex H). The current
Fortran 202Y work list WG5/N2249 includes adding interoperability with
these types as accepted work item US05. At meeting #237 in October 2025,
J3 passed paper 25-189r1 as requirements and specifications for
additional floating types.
This paper provides edits for Fortran 202Y proposal US05, "Add C
interoperability for new interchange floating point types in C".
The ISO C23 specification also added 'bool' as a keyword with an
alternate spelling of '_Bool'. This paper additionally provides edits for
Fortran 202Y to propagate this change.
2 Edits (relative to 25-007r1)
==============================
------------------------------------------------------------------------
[xv] Add to "Intrinsic modules" the sentences:
Named constants have been added to the ISO_C_BINDING module to allow
interoperability with C interchange and extended floating-point formats
defined in ISO/IEC 9899:2024 Annex H.
------------------------------------------------------------------------
[539:7-14] Replace 18.2.2 paragraph 4 with the following paragraphs:
The values of C_FLOAT, C_DOUBLE, C_LONG_DOUBLE, C_FLOAT16, C_FLOAT32,
C_FLOAT64, C_FLOAT128, C_FLOAT32X, C_FLOAT64X, C_FLOAT128X, C_DECIMAL32
C_DECIMAL64, and C_DECIMAL128 shall each be a valid value for a real
kind type parameter on the processor or shall be -1 if the companion
processor's type does not have a precision equal to the precision of any
of the Fortran processor's real kinds, -2 if the companion processor's
type does not have a range equal to the range of any of the Fortran
processor's real kinds, -3 if the companion processor's type has neither
the precision nor range of any of the Fortran processor's real kinds, -4
if there is no interoperating Fortran processor kind for other reasons,
or -5 if the companion processor does not define the corresponding C
type. The values of C_FLOAT_COMPLEX, C_DOUBLE_COMPLEX,
C_LONG_DOUBLE_COMPLEX, C_FLOAT16_COMPLEX, C_FLOAT32_COMPLEX,
C_FLOAT64_COMPLEX, C_FLOAT128_COMPLEX, C_FLOAT32X_COMPLEX,
C_FLOAT64X_COMPLEX, and C_FLOAT128X_COMPLEX shall be the same as those
of C_FLOAT, C_DOUBLE, C_LONG_DOUBLE, C_FLOAT16, C_FLOAT32, C_FLOAT64,
C_FLOAT128, C_FLOAT32X, C_FLOAT64X, and C_FLOAT128X, respectively. If
the companion processor defines the C preprocessor macros
__STDC_IEC_60559_BFP__ and __STDC_IEC_60559_TYPES__, the values of
C_FLOAT32 and C_FLOAT64 shall be the same as those of C_FLOAT and
C_DOUBLE, respectively.
------------------------------------------------------------------------
[2:6] Replace the line:
ISO/IEC 9899:2018, Programming languages -- C
with the line
ISO/IEC 9899:2024, Programming languages -- C
------------------------------------------------------------------------
[547:13] Replace the line
The C types mentioned in Table 18.2 are defined in ISO/IEC
9899:2018, 6.2.5, 7.19, and 7.20.1.
with the line
The C types mentioned in Table 18.2 are defined in ISO/IEC
9899:2024, 6.2.5, 7.22, and H.2.
------------------------------------------------------------------------
[547:table 18.2] Add the following rows to the REAL section of the table:
+--------------+-------------+
| C_FLOAT16 | _Float16 |
| C_FLOAT32 | _Float32 |
| C_FLOAT64 | _Float64 |
| C_FLOAT128 | _Float128 |
| C_FLOAT32X | _Float32x |
| C_FLOAT64X | _Float64x |
| C_FLOAT128X | _Float128x |
| C_DECIMAL32 | _Decimal32 |
| C_DECIMAL64 | _Decimal64 |
| C_DECIMAL128 | _Decimal128 |
+--------------+-------------+
------------------------------------------------------------------------
[547-548:table 18.2] Add the following rows to the COMPLEX section of
the table:
+---------------------+---------------------+
| C_FLOAT16_COMPLEX | _Float16 _Complex |
| C_FLOAT32_COMPLEX | _Float32 _Complex |
| C_FLOAT64_COMPLEX | _Float64 _Complex |
| C_FLOAT128_COMPLEX | _Float128 _Complex |
| C_FLOAT32X_COMPLEX | _Float32x _Complex |
| C_FLOAT64X_COMPLEX | _Float64x _Complex |
| C_FLOAT128X_COMPLEX | _Float128x _Complex |
+---------------------+---------------------+
------------------------------------------------------------------------
[557:table 18.4] Add the following rows after the row for
CFI_type_long_double:
+---------------------+-------------+
| CFI_type_Float16 | _Float16 |
| CFI_type_Float32 | _Float32 |
| CFI_type_Float64 | _Float64 |
| CFI_type_Float128 | _Float128 |
| CFI_type_Float32x | _Float32x |
| CFI_type_Float64x | _Float64x |
| CFI_type_Float128x | _Float128x |
| CFI_type_Decimal32 | _Decimal32 |
| CFI_type_Decimal64 | _Decimal64 |
| CFI_type_Decimal128 | _Decimal128 |
+---------------------+-------------+
------------------------------------------------------------------------
[557:table 18.4] Add the following rows after the row for
CFI_type_long_double_Complex:
+----------------------------+---------------------+
| CFI_type_Float16_Complex | _Float16 _Complex |
| CFI_type_Float32_Complex | _Float32 _Complex |
| CFI_type_Float64_Complex | _Float64 _Complex |
| CFI_type_Float128_Complex | _Float128 _Complex |
| CFI_type_Float32X_Complex | _Float32x _Complex |
| CFI_type_Float64X_Complex | _Float64x _Complex |
| CFI_type_Float128X_Complex | _Float128x _Complex |
+----------------------------+---------------------+
------------------------------------------------------------------------
[538:30] Replace two instances of:
(_Bool)
with:
(bool)
------------------------------------------------------------------------
[548:table 18.2] Replace the following:
_Bool
with:
bool
------------------------------------------------------------------------
[557:table 18.4] Replace the following:
+---------------+-------+
| CFI_type_Bool | _Bool |
+---------------+-------+
with:
+---------------+------+
| CFI_type_Bool | bool |
| CFI_type_bool | bool |
+---------------+------+
------------------------------------------------------------------------
===END===
================================================
FILE: proposals/namelist_delimiters/namelist_proposal.txt
================================================
To: J3 J3/XX-XXX
From: Marshall Ward
Subject: Require delimiters for character arrays in namelist output
Date: 19 November 2019
Proposal for Fortran Standard: 202y
1. Introduction
According to the current standard, a WRITE statement can write a
namelist file that does not conform to the namelist specification. This
happens when the namelist group contains a character array and the DELIM
specifier has a value of NONE. In particular, this is the default
behavior of a WRITE statement whose input is a namelist.
Our proposal is to require delimiters when using WRITE to write a
namelist to a file, by either requiring a value of DELIM which is
namelist-compliant, or by overriding a value of NONE when the input is a
namelist.
2. Motivation
The namelist format is described in section 13.11 of the standard, and
13.11.3.3p7 requires that character arrays in namelist groups must be
delimited with single or double quotes.
When the next effective item is of type character, the input form
consists of a sequence of zero or more rep-chars whose kind type
parameter is implied by the kind of the corresponding list item,
delimited by apostrophes or quotes.
Any namelist whose character arrays are non-delimited is non-conformant.
Any parsing of this output is therefore considered to be unformatted,
and the interpretation is at the discretion of the interpreter.
Without delimiters, many character arrays become unparseable. If a
character array contains any lexical namelist tokens, such as `&` or
`/`, then any non-delimited values may be misinterpreted as part of the
namelist object structure.
The standard acknowledges the limitations of non-delimited character
array parsing, and specifically directs the interpreter to ignore the
value of DELIM when reading a namelist (12.5.6.8).
The scalar-default-char-expr shall evaluate to APOSTROPHE, QUOTE, or
NONE. The DELIM= specifier is permitted only for a connection for
formatted input/output. It specifies the delimiter mode (12.6.2.8)
for list-directed (13.10.4) and namelist (13.11.4.2) output for the
connection. This mode has no effect on input.
However, despite the acknowledgment of the issues above, the default
behavior of a WRITE command is to produce non-delimited character
arrays. From 13.11.4.2p1,
Values in namelist output records are edited as for list-directed
output (13.10.4).
This is done despite the fact that list-directed output follows
different I/O rules for character arrays. From 13.10.3.1p7 (my
emphasis),
When the next effective item is of type character, the input form
consists of a **possibly** delimited sequence of zero or more
rep-chars whose kind type parameter is implied by the kind of the
effective item.
The namelist specification 13.11.3.3p7 deliberately omits "possibly"
from its description.
In other words, list-directed output permits non-delimited arrays,
whereas namelists do not. In addition, the default value of DELIM is to
revert back to its value in the OPEN call. From 12.5.6.8p1,
If this specifier is omitted in an OPEN statement that initiates a
connection, the default value is NONE.
The default behavior of a WRITE call using namelist data is therefore to
produce an output which is non-conformant with the namelist standard.
3. Example
Consider the program listed below, which will produce a namelist
containing a single group `sample_nml`, containing a single character
array, `input`.
program writenml
implicit none
character(len=20) :: input
namelist /sample_nml/ input
input = trim("some/path/to/file")
open(5, file="out.nml")
write(5, nml=sample_nml)
end program writenml
According to the interpretation above, the absence of a DELIM argument
means that `input` is formatted with no delimiter. A
standard-conforming output would be
&SAMPLE_NML
INPUT = some/path/to/file
/
For this example, we have used the output produced by the Intel Fortran
Compiler 19.0.5.281.
Now consider the following program, which reads this namelist.
program readnml
implicit none
character(len=20) :: input
namelist /sample_nml/ input
open(5, file='out.nml')
read(5, nml=sample_nml)
open(6, file='new.nml')
write(6, nml=sample_nml)
end program readnml
The namelist `new.nml` produced by this program is the following.
&SAMPLE_NML
INPUT = some
/
The namelist group `sample_nml` is terminated after the first `/` token,
and any characters following the token are ignored.
Although the interpretation is correct, it also means that a write
statement of the following form
write(unit, nml=filename)
where the DELIM argument is unset will produce namelists which are
non-conforming. The fact that this is not only possible, but is the
default behavior, is counterintuitive and is likely to introduce errors
into namelist I/O operations.
As an aside, we note that GNU Fortran explicitly breaks from the
standard and does produce a quote-delimited namelist, such as the one
shown below.
&SAMPLE_NML
INPUT="some/path/to/file ",
/
This namelist above was produced by GNU Fortran 9.2.1.
4. Proposal
We propose one of the following additions to the *io-control-spec-list*,
detailed in 12.6.2.1.
A. If *namelist-group-name* appears, then a DELIM= specifier with the
value of either APOSTROPHE or QUOTE shall also appear.
Option A would take the current recommended advice to always use DELIM
when writing namelist output and turn it into an explicit rule. The
following statement would constitute an error
write(unit, nml=filename)
and would require the user to include a DELIM argument, e.g.
write(unit, nml=filename, delim="quote")
This would also mean that currently compliant code missing a DELIM would
be non-compliant, and may require modifications if used by future
interpreters.
B. If *namelist-group-name* appears and a DELIM= specifier has the value
of NONE, then this value is ignored and the data transfer uses a
value of APOSTROPHE.
Option B would change the behavior of existing standard-compliant
interpreters, in that non-delimited character arrays would be replaced
with apostrophe-delimited arrays. But existing source code would
otherwise remain compliant and continue to compile on both older and
newer interpreters.
5. Reference
Discussion of this issue on the Intel Fortran forums:
https://software.intel.com/en-us/forums/intel-fortran-compiler/topic/831685
Discussion of GNU Fortran's decision to use quote delimiters:
https://gcc.gnu.org/ml/gcc-patches/2014-03/msg00030.html
Initial submission and discussion to the J3 Fortran Github repository:
https://github.com/j3-fortran/fortran_proposals/pull/94
================================================
FILE: proposals/namespace_modules/19-246.txt
================================================
To: J3 J3/19-246
From: Ondrej Certik
Subject: Namespace For Modules
Date: 2019-October-16
Proposal for Fortran Standard: 202y (NOT 202x)
1. Introduction
The proposal is to allow import a module as a namespace and access its
members using the % operator. Example:
use, namespace :: utils
...
call utils%savetxt(...)
Where `utils` is the only name that is imported in the local namespace.
`savetxt` is not accesible directly, only via `utils%`.
2. Motivation
Fortran module usage is equivalent to Python:
Python Fortran
from A import foo use A, only: foo
from A import foo as Afoo use A, only: Afoo => foo
from A import * use A
Except:
Python Fortran
import A N/A
import A as B N/A
This proposal proposes to fill in the missing functionality as follows:
Python Fortran
import A use, namespace :: A
import A as B use, namespace :: B => A
3. Use Cases
3.1 Same function names in multiple modules
In Python a very common idiom is:
import math
import numpy as np
import sympy as sym
...
e1 = np.sin(np.pi) # NumPy expression
e2 = math.sin(math.pi) # Built-in Python math expression
e3 = sym.sin(sym.pi) # SymPy expression
In Fortran currently one has to do:
use math, only: math_sin => sin, math_pi => pi
use numpy, only: np_sin => sin, np_pi => pi
use sympy, only: sym_sin => sin, sym_pi => pi
...
e1 = np_sin(np_pi) ! NumPy expression
e2 = math_sin(math_pi) ! Built-in Python math expression
e3 = sym_sin(sym_pi) ! SymPy expression
With this proposal one could also do:
use, namespace :: math
use, namespace :: np => numpy
use, namespace :: sym => sympy
...
e1 = np%sin(np%pi) ! NumPy expression
e2 = math%sin(math%pi) ! Built-in Python math expression
e3 = sym%sin(sym%pi) ! SymPy expression
3.2 Need to import lots of functions from a module
Exising code (https://github.com/certik/fortran-utils/blob/
b43bd24cd421509a5bc6d3b9c3eeae8ce856ed88/src/linalg.f90):
use lapack, only: dsyevd, dsygvd, ilaenv, zgetri, zgetrf, zheevd, &
dgeev, zgeev, zhegvd, dgesv, zgesv, dgetrf, dgetri, dgelsy, &
zgelsy, dgesvd, zgesvd, dgeqrf, dorgqr, dpotrf, dtrtrs
...
call dgeev('N', 'V', n, At, lda, wr, wi, vl, ldvl, vr, ldvr, &
work, lwork, info)
...
call dgetrf(n, n, Amt, lda, ipiv, info)
...
Instead, one can write it as:
use, namespace :: lapack
...
call lapack%dgeev('N', 'V', n, At, lda, wr, wi, vl, ldvl, vr, ldvr, &
work, lwork, info)
...
call lapack%dgetrf(n, n, Amt, lda, ipiv, info)
...
Then when another subroutine must be called from the `lapack` module, one
can just call it, without having to modify the `use` statement.
================================================
FILE: proposals/namespace_modules/20-108.txt
================================================
To: J3 J3/20-108
From: Ondrej Certik
Subject: Namespace For Modules
Date: 2020-February-23
Proposal for Fortran Standard: 202y (NOT 202x)
1. Introduction
The proposal is to allow import a module as a namespace and access its
members using the % operator. Example:
use, namespace :: utils
...
call utils%savetxt(...)
Where `utils` is the only name that is imported in the local namespace.
`savetxt` is not accesible directly, only via `utils%`.
This proposal originated at the J3 GitHub repository at [1].
2. Motivation
Fortran module usage is equivalent to Python:
Python Fortran
from A import foo use A, only: foo
from A import foo as Afoo use A, only: Afoo => foo
from A import * use A
Except:
Python Fortran
import A N/A
import A as B N/A
This proposal proposes to fill in the missing functionality as follows:
Python Fortran
import A use, namespace :: A
import A as B use, namespace :: B => A
3. Use Cases
3.1 Same function names in multiple modules
In Python a very common idiom is:
import math
import numpy as np
import sympy as sym
...
e1 = np.sin(np.pi) # NumPy expression
e2 = math.sin(math.pi) # Built-in Python math expression
e3 = sym.sin(sym.pi) # SymPy expression
In Fortran currently one has to do:
use math, only: math_sin => sin, math_pi => pi
use numpy, only: np_sin => sin, np_pi => pi
use sympy, only: sym_sin => sin, sym_pi => pi
...
e1 = np_sin(np_pi) ! NumPy expression
e2 = math_sin(math_pi) ! Built-in Python math expression
e3 = sym_sin(sym_pi) ! SymPy expression
With this proposal one could also do:
use, namespace :: math
use, namespace :: np => numpy
use, namespace :: sym => sympy
...
e1 = np%sin(np%pi) ! NumPy expression
e2 = math%sin(math%pi) ! Built-in Python math expression
e3 = sym%sin(sym%pi) ! SymPy expression
3.2 Need to import lots of functions from a module
Existing code (https://github.com/certik/fortran-utils/blob/
b43bd24cd421509a5bc6d3b9c3eeae8ce856ed88/src/linalg.f90):
use lapack, only: dsyevd, dsygvd, ilaenv, zgetri, zgetrf, zheevd, &
dgeev, zgeev, zhegvd, dgesv, zgesv, dgetrf, dgetri, dgelsy, &
zgelsy, dgesvd, zgesvd, dgeqrf, dorgqr, dpotrf, dtrtrs
...
call dgeev('N', 'V', n, At, lda, wr, wi, vl, ldvl, vr, ldvr, &
work, lwork, info)
...
call dgetrf(n, n, Amt, lda, ipiv, info)
...
Instead, one can write it as:
use, namespace :: lapack
...
call lapack%dgeev('N', 'V', n, At, lda, wr, wi, vl, ldvl, vr, ldvr, &
work, lwork, info)
...
call lapack%dgetrf(n, n, Amt, lda, ipiv, info)
...
Then when another subroutine must be called from the `lapack` module, one
can just call it, without having to modify the `use` statement.
4. References
[1] https://github.com/j3-fortran/fortran_proposals/issues/1
================================================
FILE: proposals/protected_attribute.txt
================================================
To: J3 J3/##-###
From: Balint Aradi
Subject: Protected attribute for derived type components
Date: 2019-October-21
Proposal for Fortran Standard: 202y (NOT 202x)
1. Introduction
The proposal is to allow specify the protected attribute for components in
derived types. Example:
type :: prot_t
integer, allocatable, protected :: array(:)
end type prot_t
2. Motivation
Data hiding using derived types with private components allows programmer
to provide robust types, where internals can only be changed in controlled
fashion. The usual implementation is to provide setter and getter routines
for writing and reading components. Both operations involve copying the
passed data, which can be inefficient when storing large arrays in the
derived type instance. While in the setter routine the copying serves
robustness by "disentangling" the data stored in the derived type from the
original data, the getter routine and the connected copy operation might be
superfluous, when the consumer only wants to read but not modify the data
stored in the derived type intance.
By allowing for a direct read-only access, one could enhance efficiency in
those cases without sacrificing the consistency of the encapsulated
data. Direct access is possible with current Fortran already, but only if
the respective derived type component is public. This would jeopardize data
consistency, though, as a consumer could change the respective component
arbitrarily, without using the provided setter routine.
This proposal suggests to allow the "protected" attribute already used for
module variables being used for derived type components as well. It would
also remedy the asymmetry between the attributes "private"/"public" and the
attribute "protected", as the former two can be applied to both, module
variables and derived type components, while the latter only for module
variables so far.
3. Use Cases
Derived types storing large amount of data could enable read-only access to
components without the necessity of a getter routine and the connected copy
operation:
module data_m
implicit none
type :: prot_t
! Large array component
integer, allocatable, protected :: array(:)
contains
procedure :: set
end type prot_t
contains
subroutine set(this, array)
type(prot_t), intent(out) :: this
this%array = array
end subroutine set
end module data_m
program use_data
use data_m
implicit none
type(prot_t) :: storage
integer, allocatable :: large_array(:)
! Filling up and allocating the large array
! ...
! Storing the large array in the derived type instance
call storage%set(large_array)
! Accessing large array stored in the derived type directly
! No getter routine and no copy necessary
! Dummy argument of the called routine must be intent(in)
call some_routine_processing_but_not_changing_the_array(storage%array)
! Inconsistent change, consumer is supposed to call set() to change
! encapsulated data.
! Uncommenting the next line should trigger a compiler error.
!storage%array(1) = -1
end program use_data
4. Online discussion
This proposal derived from the discussion on the j3-fortran github page:
https://github.com/j3-fortran/fortran_proposals/issues/16
================================================
FILE: proposals/run-time_polymorphism/Examples/AppendixA/taylor.f90
================================================
! Fortran implementation of the Taylor series example program based on
! subclassing given in Appendix A of the proposal "Improved run-time
! polymorphism for Fortran".
!
module derivs
type, abstract :: Deriv
contains
procedure(pderiv), deferred, nopass :: deriv1
end type Deriv
abstract interface
subroutine pderiv()
end subroutine pderiv
end interface
type, extends(Deriv) :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, extends(DerivF) :: HDerivF
contains
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
type, extends(Deriv) :: DerivG
contains
procedure, nopass :: deriv1 => deriv1g
end type DerivG
type, extends(DerivG) :: HDerivG
contains
procedure, nopass :: deriv2 => deriv2g
end type HDerivG
contains
subroutine deriv1f()
write(*,*) ' 1st derivative of function F!'
end subroutine deriv1f
subroutine deriv2f()
write(*,*) ' 2nd derivative of function F!'
end subroutine deriv2f
subroutine deriv1g()
write(*,*) ' 1st derivative of function G!'
end subroutine deriv1g
subroutine deriv2g()
write(*,*) ' 2nd derivative of function G!'
end subroutine deriv2g
end module derivs
module series
use derivs, only: Deriv, HDerivF, HDerivG
type :: Taylor
class(Deriv), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type, extends(Taylor) :: HTaylor
contains
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
contains
subroutine term1(self)
class(Taylor), intent(in) :: self
call self%calc%deriv1()
end subroutine term1
subroutine evaluate(self)
class(Taylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
end subroutine evaluate
subroutine hterm2(self)
class(HTaylor), intent(in) :: self
select type ( calc => self%calc )
class is ( HDerivF )
call calc%deriv2()
class is ( HDerivG )
call calc%deriv2()
class default
write(*,*) 'Unknown type!'
end select
end subroutine hterm2
subroutine hevaluate(self)
class(HTaylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
call self%term2()
end subroutine hevaluate
end module series
program client
use derivs, only: DerivG, HDerivG, Deriv
use series, only: Taylor, HTaylor
class(Deriv), allocatable :: derv
class(Taylor), allocatable :: teval
derv = DerivG()
teval = Taylor(derv)
call teval%evaluate()
write(*,*)
derv = HDerivG()
teval = HTaylor(derv)
call teval%evaluate()
end program client
================================================
FILE: proposals/run-time_polymorphism/Examples/AppendixB/taylor.f90
================================================
! Fortran implementation of the Taylor series example program based on
! subtyping given in Appendix B of the proposal "Improved run-time
! polymorphism for Fortran".
!
module interfaces
abstract interface :: IDeriv
subroutine deriv1()
end subroutine deriv1
end interface IDeriv
abstract interface, extends(IDeriv) :: IHDeriv
subroutine deriv2()
end subroutine deriv2
end interface IHDeriv
end module interfaces
module derivs
use interfaces, only: IDeriv, IHDeriv
type, implements(IDeriv) :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, implements(IHDeriv) :: HDerivF
contains
procedure, nopass :: deriv1 => deriv1f
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
type, implements(IDeriv) :: DerivG
contains
procedure, nopass :: deriv1 => deriv1g
end type DerivG
type, implements(IHDeriv) :: HDerivG
contains
procedure, nopass :: deriv1 => deriv1g
procedure, nopass :: deriv2 => deriv2g
end type HDerivG
contains
subroutine deriv1f()
write(*,*) " 1st derivative of function F!"
end subroutine deriv1f
subroutine deriv2f()
write(*,*) " 2nd derivative of function F!"
end subroutine deriv2f
subroutine deriv1g()
write(*,*) " 1st derivative of function G!"
end subroutine deriv1g
subroutine deriv2g()
write(*,*) " 2nd derivative of function G!"
end subroutine deriv2g
end module derivs
module series
use interfaces, only: IDeriv, IHDeriv
type :: Taylor
class(IDeriv), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type :: HTaylor
class(IHDeriv), allocatable :: calc
contains
procedure :: term1 => hterm1
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
contains
subroutine term1(self)
class(Taylor), intent(in) :: self
call self%calc%deriv1()
end subroutine term1
subroutine evaluate(self)
class(Taylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
end subroutine evaluate
subroutine hterm1(self)
class(HTaylor), intent(in) :: self
call self%calc%deriv1()
end subroutine hterm1
subroutine hterm2(self)
class(HTaylor), intent(in) :: self
call self%calc%deriv2()
end subroutine hterm2
subroutine hevaluate(self)
class(HTaylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
call self%term2()
end subroutine hevaluate
end module series
program client
use derivs, only: DerivG, HDerivG
use series, only: Taylor, HTaylor
type(Taylor), allocatable :: teval
type(HTaylor), allocatable :: hteval
teval = Taylor( DerivG() )
call teval%evaluate()
write(*,*)
hteval = HTaylor( HDerivG() )
call hteval%evaluate()
end program client
================================================
FILE: proposals/run-time_polymorphism/Examples/AppendixB/taylor.java
================================================
// Java implementation of the Taylor series example program based on
// subtyping given in Appendix B of the proposal "Improved run-time
// polymorphism for Fortran".
//
interface IDeriv {
void deriv1();
}
interface IHDeriv extends IDeriv {
void deriv2();
}
class DerivF implements IDeriv {
public void deriv1() {
System.out.println(" 1st derivative of function F!");
}
}
class HDerivF implements IHDeriv {
public void deriv1() {
System.out.println(" 1st derivative of function F!");
}
public void deriv2() {
System.out.println(" 2nd derivative of function F!");
}
}
class DerivG implements IDeriv {
public void deriv1() {
System.out.println(" 1st derivative of function G!");
}
}
class HDerivG implements IHDeriv {
public void deriv1() {
System.out.println(" 1st derivative of function G!");
}
public void deriv2() {
System.out.println(" 2nd derivative of function G!");
}
}
class Taylor {
IDeriv calc;
Taylor(IDeriv calculator) {
calc = calculator;
}
public void term1() {
calc.deriv1();
}
public void evaluate() {
System.out.println("Evaluating Taylor series using");
term1();
}
}
class HTaylor {
IHDeriv calc;
HTaylor(IHDeriv calculator) {
calc = calculator;
}
public void term1() {
calc.deriv1();
}
public void term2() {
calc.deriv2();
}
public void evaluate() {
System.out.println("Evaluating Taylor series using");
term1();
term2();
}
}
class ClientApp {
public static void main(String[] args) {
Taylor eval = new Taylor( new DerivG() );
eval.evaluate();
System.out.println("");
HTaylor heval = new HTaylor( new HDerivG() );
heval.evaluate();
}
}
================================================
FILE: proposals/run-time_polymorphism/Examples/AppendixB/taylor.rs
================================================
// Rust implementation of the Taylor series example program based on
// subtyping given in Appendix B of the proposal "Improved run-time
// polymorphism for Fortran".
//
pub mod interfaces {
pub trait IDeriv {
fn deriv1(&self);
}
pub trait IHDeriv {
fn deriv1(&self);
fn deriv2(&self);
}
}
pub mod derivs {
use interfaces::IDeriv;
use interfaces::IHDeriv;
pub struct DerivF {
}
impl IDeriv for DerivF {
fn deriv1(&self) {
println!(" 1st derivative of function F!");
}
}
pub struct HDerivF {
}
impl IHDeriv for HDerivF {
fn deriv1(&self) {
println!(" 1st derivative of function F!");
}
fn deriv2(&self) {
println!(" 2nd derivative of function F!");
}
}
pub struct DerivG {
}
impl IDeriv for DerivG {
fn deriv1(&self) {
println!(" 1st derivative of function G!");
}
}
pub struct HDerivG {
}
impl IHDeriv for HDerivG {
fn deriv1(&self) {
println!(" 1st derivative of function G!");
}
fn deriv2(&self) {
println!(" 2nd derivative of function G!");
}
}
}
pub mod series {
use interfaces::IDeriv;
use interfaces::IHDeriv;
pub struct Taylor {
pub calc: Box<dyn IDeriv>
}
impl Taylor {
pub fn term1(&self) {
self.calc.deriv1();
}
pub fn evaluate(&self) {
println!("Evaluating Taylor series using");
self.term1();
}
}
pub struct HTaylor {
pub calc: Box<dyn IHDeriv>
}
impl HTaylor {
pub fn term1(&self) {
self.calc.deriv1();
}
pub fn term2(&self) {
self.calc.deriv2();
}
pub fn evaluate(&self) {
println!("Evaluating Taylor series using");
self.term1();
self.term2();
}
}
}
fn main() {
use derivs::DerivG;
use derivs::HDerivG;
use series::Taylor;
use series::HTaylor;
let derivg = Box::new( DerivG{} );
let eval = Box::new( Taylor{calc: derivg} );
eval.evaluate();
println!("");
let hderivg = Box::new( HDerivG{} );
let heval = Box::new( HTaylor{calc: hderivg} );
heval.evaluate();
}
================================================
FILE: proposals/run-time_polymorphism/Examples/Text/taylor_basic.f90
================================================
module derivs
type :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
contains
subroutine deriv1f()
write(*,*) ' 1st derivative of function F!'
end subroutine deriv1f
end module derivs
module series
use derivs, only: DerivF
type :: Taylor
type(DerivF), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
contains
subroutine term1(self)
class(Taylor), intent(in) :: self
call self%calc%deriv1()
end subroutine term1
subroutine evaluate(self)
class(Taylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
end subroutine evaluate
end module series
program client
use derivs, only: DerivF
use series, only: Taylor
type(Taylor), allocatable :: teval
teval = Taylor( DerivF() )
call teval%evaluate()
end program client
================================================
FILE: proposals/run-time_polymorphism/Fortran_OOP.bib
================================================
@INPROCEEDINGS{Snyder86,
author = {Alan Snyder},
title = {Encapsulation and Inheritance in Object-Oriented
Programming Languages},
booktitle = {OOPSLA'86 Proceedings},
year = {1986},
month = "September",
pages = {38--45},
publisher = "ACM"
}
@book{Bates_et_al_09,
author = "Bates, Bert and Sierra, Kathy and Freeman, Eric and
Robson, Elisabeth",
title = "Head First Design Patterns",
year = "2009",
publisher = "O'Reilly Media",
address = ""
}
@book{Gamma_et_al_94,
author = "Gamma, Erich and Helm, Richard and Johnson, Ralph and
Vlissides, John",
title = "Design Patterns.
Elements of Reusable Object-Oriented Software",
year = "1994",
publisher = "Prentice Hall",
address = ""
}
@book{Martin_03,
author = "Martin, Robert C.",
title = "Agile Software Development:
Principles, Patterns, and Practices",
year = "2002",
publisher = "Pearson",
address = ""
}
@misc{Weck_Szyperski,
author = "Weck, Wolfgang and Szyperski, Clemens",
title = "{Do We Need Inheritance?}",
howpublished = {\url{https://www.researchgate.net/publication/2297653_Do_We_Need_Inheritance}},
note = {Accessed February 4, 2020},
}
================================================
FILE: proposals/run-time_polymorphism/Fortran_OOP.tex
================================================
\documentclass[11pt,oneside]{article}
\usepackage[a4paper, total={6.5in, 9in}]{geometry}
\usepackage{natbib}
\usepackage{url}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[title]{appendix}
\frenchspacing
\definecolor{codegreen}{rgb}{0,0.6,0}
\definecolor{codegray}{rgb}{0.5,0.5,0.5}
\definecolor{codepurple}{rgb}{0.58,0,0.82}
\definecolor{backcolour}{rgb}{0.95,0.95,0.92}
\lstdefinestyle{mystyle}{
% backgroundcolor=\color{backcolour},
commentstyle=\color{codegreen},
% keywordstyle=\color{magenta},
numberstyle=\tiny\color{codegray},
stringstyle=\color{codepurple},
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
% numbers=left,
numbers=none,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2
}
\lstset{style=mystyle}
\begin{document}
\title{Improved run-time polymorphism for Fortran \\ [1em]
\large{Proposal to J3 for inclusion into Fortran 202y}
}
\author{K. Kifonidis}
\maketitle
\abstract{A case is made for extending Fortran's support for
object-oriented (OO) programming (i.e. run-time polymorphism) in
order to enable and encourage the use of best practices for the
design and implementation of flexible OO software, and to improve
the safety and efficiency of the language. It is proposed to
introduce multiple inheritance of specification, in order to
supplement the single inheritance of implementation that is already
contained in the language. The new feature extends Fortran's
abstract interfaces and derived types by functionality akin to what
is present in Java, and some other, recent, languages. It is
essential for writing code that conforms to the dependency inversion
principle of OO programming. This will encourage the development of
software that forgoes dependency upon concretions in favor of
dependency on abstractions. The decoupling of classes that can be
achieved in this way will lead to significantly more flexible and
extensible numerical codes, that are also more efficient. The new
feature enables a programming style that dispenses with the use of
implementation inheritance, and therefore helps to eliminate type
conflicts whose resolution requires ``select type'' (down-casting)
statements. These, and their associated run-time overhead, have been
a frequent gripe of Fortran OO programmers since the introduction of
Fortran 2003. As a bonus, the feature should be relatively easy to
implement in Fortran compilers that adhere to at least the Fortran
2003 standard.}
\section{Introduction}
Over the last decades, a significant body of experience has
accumulated concerning the practical use of object-oriented
programming (OOP). This experience has markedly shaped the design of
some very recent programming languages, like Rust and Go, and it has
also led to some notable revision of our notions of what actually
constitutes OOP. In this modern view, the very essence of OOP, and in
fact its ultimate upshot, is the use of (run-time) polymorphism to
manage (i.e. minimize) code dependencies
\cite{Martin_03,Bates_et_al_09}. Viewed in this way, OOP is simply a
means to organize code so that it achieves a maximum amount of
\emph{decoupling}.
The crucial idea in this context is that polymorphism has the unique
ability to allow one to invert the flow of dependency in a computer
code, which normally points from higher level modules to lower level
modules (read ``classes'' in the OOP context). Polymorphism makes it
possible to replace (``invert'') the dependency of a higher level
class upon a lower level class by a dependency of both these classes
upon a pure abstraction, which is called an interface (or a contract,
protocol, or trait). Thereby, high-level policy gets decoupled from
low-level implementation detail. This is known as the dependency
inversion principle \cite{Martin_03}. If strictly followed, this
principle leads to the development of loosely coupled, easily
extensible, easily testable, modular, maintainable, and thus
future-proof software. It is this decoupling which allows for the
re-usability and flexibility of well-written OO code.
The situation encountered in practice is usually a different one,
though. Experience has shown that OO software which is written in
Fortran 2003 (and its successors) seldom displays these desirable
characteristics. It will be argued in the following that it is the
combination of a lack of appropriate features in the language, for
encouraging (or even enforcing) a programming style that upholds the
dependency inversion principle, and the consequent indiscriminate use
of features that the language \emph{does} provide (in particular
inheritance of implementation), that has to be blamed for this
situation.
\section{Deficiencies in Fortran 2018 addressed by this proposal}
\label{sect:F08_deficits}
\subsection{No explicit distinction between different inheritance types}
In statically typed languages, like Fortran, run-time polymorphism is
tightly bound to inheritance. In order to manage dependencies in the
way it was described above, the users of these languages must employ
some form of inheritance mechanism. It is important to realize that it
is \emph{inheritance of (object) specification}, i.e. inheritance of
interfaces, that is required for this purpose. It is this (restricted)
form of inheritance that is today viewed as being indispensable for
OOP. Interface inheritance allows for the aforementioned
interface-based programming style, that embodies the dependency
inversion principle.
Fortran, on the other hand, makes exclusive use of \emph{inheritance
of implementation}, i.e. inheritance of classes. A class encompasses
both an interface (given by the union of its methods' signatures,
through which it communicates with the external world), \emph{and} the
implementation details of an OO algorithm (in the form of data
variables, and the implementation bodies of its methods). A class is
therefore not a proper abstraction (for other classes or procedures)
to depend upon. It is not sufficiently generic. It contains
implementation-dependent detail, which other classes end up being
needlessly coupled to, if they make use of it via either inheritance
or object composition. Only the class's interface is free from such
detail and should be depended upon for these purposes, to achieve a
maximum amount of decoupling in an application.
Fortran presently makes no explicit distinction between implementation
inheritance and specification inheritance. The latter can only be
\emph{emulated} in Fortran by \emph{re-purposing} class inheritance,
and exploiting (or rather abusing) the fact that classes intermingle
implementation with specification. Fortran offers abstract types
(i.e. abstract classes) for related use cases, which can contain
deferred (i.e. abstract) procedures, for which ``abstract interfaces''
have to be specified by the user. However, abstract classes (as all
other classes) are explicitly allowed to \emph{also} contain variables
and concrete methods, i.e. state, as well as implementation code,
which makes abstract classes dangerous to depend upon for inheriting
specification from.
In contrast to Java, C\#, D, Swift, Rust, Go and some other modern
languages, Fortran does not offer a means to inherit specification
directly from its ``abstract interfaces'', which --- though available,
and guaranteed to be completely free of implementation detail --- play
only a subordinate, instead of a cardinal role in the language. Hence
it is not possible to enforce, at the language level, the strict
separation of the implementation of an OO algorithm from its
interface, that is required for adherence to the dependency inversion
principle.
\subsection{Problems due to the lack of distinction between inheritance types}
\label{sect:problems}
Interface inheritance has the sole purpose of enabling polymorphism,
in order to invert dependencies and thereby make parts of an algorithm
interchangeable (i.e. to achieve high-level code reuse
\cite{Gamma_et_al_94}). This is also called \emph{sub-typing}. In
contrast, class inheritance is meant to be used primarily for sharing
common implementation code between parent and child classes. This is
also called \emph{sub-classing}, and can be viewed as a form of
low-level code reuse.
There is a significant body of evidence that demonstrates that
sub-classing is a dangerous practice, which, moreover, is not
essential to OOP. Snyder \cite{Snyder86} showed already in the
eighties that sub-classing breaks encapsulation. Weck and Szyperski
re-emphasized this \cite{Weck_Szyperski}. They proposed to abolish
sub-classing, since they regard it as being prone to abuse. Even
moderately incautious use of sub-classing typically leads to rigid,
brittle code, that is tightly coupled to the details of concrete
(implementation) classes, and is therefore unmaintainable and
in-extensible. This is especially the case when sub-classing is used in
combination with method overriding, or changes to a base object's
state \cite{Weck_Szyperski}. Moreover, when sub-classing is employed
along with object composition in an application (which is inevitable
in practice), type conflicts can often result. These can then only be
resolved by down-casting, i.e. by the use of \texttt{select type}
statements in Fortran, which lead to unnecessary run-time
overhead. This can be viewed as resulting from a violation of the
dependency inversion principle, which states that inheritance should
be used \emph{exclusively} for sub-typing.
All these issues could be avoided, if Fortran would be extended to
allow for (multiple) inheritance of interfaces, in order to provide
its programmers with easy and safe access to sub-typing. Sub-classing
(i.e. type extension) could then be mostly shunned in the development
of new codes. Clear guidelines could then be given to Fortran
programmers to rely instead on object composition for low-level, and
on the features proposed in this proposal for high-level code reuse,
in the vast majority of their code. A coding style that is in
accordance with the dependency inversion principle would thus be
encouraged that would eliminate type conflicts, the need for
\texttt{select type} statements, and their run-time overhead. A
potential drawback of object composition is the need for some
boilerplate code, i.e. for methods that delegate functionality to
composed classes. However, efficiency can still be expected to improve
over present Fortran OOP codes, especially in cases where
\texttt{select type} statements appear in low-level code, e.g. in
computational kernels.
The importance of such a coding style is actually not some entirely
new insight. Among the very first recommendations that one finds in
the pioneering work of Gamma et al. \cite{Gamma_et_al_94} on OO design
patterns are the statements ``program to an interface not an
implementation'' and ``favor object composition over class
inheritance''. What had apparently not been recognized widely is that
these are also recommendations for language design. This has changed
recently, with the availability of the Rust and Go languages. In these
languages, interface inheritance is the \emph{only} type of inheritance
that is supported. These languages therefore \emph{enforce} an OOP
style that is in accordance with the dependency inversion principle.
\section{Proposed additions to Fortran 202y}
\label{sect:propositions}
The new features proposed to solve the problems discussed in the last
section are
\begin{itemize}
\item
A possibility to declare \emph{named} versions of Fortran's abstract
interfaces, from which derived types would then be able to inherit
specification.
\item
An \texttt{extends} attribute-specifier for the declaration header of
these named abstract interfaces, to allow hierarchies of such (named)
abstract interfaces to be built\footnote{Hierarchies of interfaces
do not pose the dangers that sub-classing poses, as only
\emph{specification} is shared, see \cite{Weck_Szyperski}.}.
\item
A new \texttt{implements} type-attribute-specifier for derived types, to
enable these types to inherit specification from one or more named
abstract interfaces.
\item
An extension of Fortran's \texttt{class} declaration-type-specifier
for polymorphic variables, to accept named abstract interfaces. This
would enable one to declare polymorphic variables of named abstract
interfaces, in order to make use of sub-typing polymorphism.
\end{itemize}
\subsection{Extended declaration syntax for abstract interfaces}
\label{sect:declare}
The following listing shows an example of an extended syntax for
interface declarations. In a module named \texttt{interfaces}, four
named abstract interfaces are declared: \texttt{ISolver},
\texttt{IPrinter}, \texttt{IClient}, and
\texttt{IRelaxationSolver}. \texttt{ISolver} and \texttt{IPrinter}
contain the declarations of subroutines \texttt{solve\_system}, and
\texttt{print\_result}, respectively. Notice that \texttt{IClient}, on
the other, hand contains declarations for \emph{two} procedures:
subroutines \texttt{solve\_system}, \emph{and} \texttt{print\_result},
which it inherits from \texttt{ISolver} and \texttt{IPrinter},
respectively, by means of the \texttt{extends} attribute-specifier.
\begin{lstlisting}[language=Fortran]
module interfaces
abstract interface :: ISolver
subroutine solve_system(a,b,x)
real, dimension(:,:), intent(in) :: a
real, dimension(:), intent(in) :: b
real, dimension(:), intent(out) :: x
end subroutine solve_system
end interface ISolver
abstract interface :: IPrinter
subroutine print_result(x)
real, dimension(:), intent(in) :: x
end subroutine print_result
end interface IPrinter
abstract interface, extends(ISolver,IPrinter) :: IClient
end interface IClient
abstract interface :: IRelaxationSolver
subroutine driver(self,d,rhs,x)
import :: IRelaxationSolver
class(IRelaxationSolver), intent(in) :: self
real, dimension(:,:,:,:), intent(in) :: d
real, dimension(:,:,:), intent(in) :: rhs
real, dimension(:,:,:), intent(out) :: x
end subroutine driver
subroutine relax(blksolver,d,rhs,x)
import :: ISolver
class(ISolver), intent(in) :: blksolver
real, dimension(:,:,:,:), intent(in) :: d
real, dimension(:,:,:), intent(in) :: rhs
real, dimension(:,:,:), intent(out) :: x
end subroutine relax
end interface IRelaxationSolver
end module interfaces
\end{lstlisting}
\label{list:interface}
Finally, the declaration of the \texttt{IRelaxationSolver} interface
illustrates that a named abstract interface may depend on other named
abstract interfaces, not only via an \texttt{extends}
attribute-specifier (as shown above), but also through the procedure
declarations that it contains. Namely, the latter may contain
polymorphic arguments that are declared with the help of the
\texttt{class} declaration-type-specifier (see
Sect.~\ref{sect:declarations}), to give these procedures access to
either the data fields (variables) of the type that \emph{implements}
the abstract interface (i.e. to the descendant of that interface) or
to the descendants of \emph{other} abstract interfaces. In these
cases, Fortran's \texttt{import} statement would be required in order
to bring such external names into the procedure declarations' own
scope.
Other ways to express and implement the proposed functionality are
possible, and need to be considered. The one discussed here has the
advantages that abstract interfaces are already a part of the language
and are merely extended here by functionality that does not affect
their other uses. It does, however, elevate their status in the
language as it makes them central to expressing interface
inheritance. This syntax also makes the distinction between sub-typing
and sub-classing apparent, which is a major plus. It has the further
advantage that named abstract interfaces could also be used in future
extensions of the language, e.g. in connection with \emph{intrinsic}
types, and with generics. This is the approach taken in the Swift
programming language where (named) abstract interfaces (called
``protocols'' there) are so central to its functionality, that Swift
has been called a ``protocol-based'' language. It is not our purpose
here to delve deeper into syntactic or extensibility issues. We rather
need some syntax that is able to express the following code examples,
and the present one does so satisfactorily.
\subsection{Facility to implement interfaces}
Once a named abstract interface has been declared, it can be
implemented by a derived type that needs to conform to that interface,
by using the new \texttt{implements} type-attribute-specifier as
follows
\begin{lstlisting}[language=Fortran]
module lu_decomp
use interfaces, only: ISolver
type, implements(ISolver) :: LUDecomposition
contains
procedure, nopass :: solve_system
end type LUDecomposition
contains
subroutine solve_system(a,b,x)
real, dimension(:,:), intent(in) :: a
real, dimension(:), intent(in) :: b
real, dimension(:), intent(out) :: x
! Implementation of LU decomposition goes here
end subroutine solve_system
end module lu_decomp
\end{lstlisting}
In case the derived type is abstract, it is allowed to provide an only
partial implementation of the interface(s) that it implements. Any
non-abstract derived type that extends the abstract type must,
however, provide a full implementation.
\subsection{Polymorphism via sub-typing}
\label{sect:declarations}
To make actual use of the sub-typing polymorphism that we have just
set up, polymorphic variables of named abstract interfaces would then
be declared with the help of the (extended) \texttt{class}
declaration-type-specifier; for instance, as arguments of a procedure,
or within another derived type. They could then be used in the actual
implementation of this derived type's bound procedures, e.g. as
follows:
\begin{lstlisting}[language=Fortran]
type, implements(IClient) :: Client
class(ISolver), allocatable :: solver
class(IPrinter), pointer :: printer => null()
contains
procedure, nopass :: solve_system
procedure, nopass :: print_result
end type Client
\end{lstlisting}
Here, two polymorphic variables, \texttt{solver} and \texttt{printer},
that conform to the \texttt{ISolver} and \texttt{IPrinter} interfaces,
respectively, are declared for the purpose of object composition
within type \texttt{Client}, which itself implements the
\texttt{IClient} interface, and thus has to provide implementations
for the procedures \texttt{solve\_system} and \texttt{print\_result}
(whose actual code is omitted here, and would simply employ delegation
to \texttt{solver} and \texttt{printer} to provide the required
functionality).
Notice also, that the proposed features allow multiple interface
inheritance. In case \texttt{Client} has to conform to either
\texttt{ISolver} or \texttt{IPrinter}, one could, for instance,
provide an implementation much as in the last example, but would use
the \texttt{implements} specifier as follows
\begin{lstlisting}[language=Fortran]
type, implements(ISolver,IPrinter) :: Client
class(ISolver), allocatable :: solver
class(IPrinter), pointer :: printer => null()
contains
procedure, nopass :: solve_system
procedure, nopass :: print_result
end type Client
\end{lstlisting}
The next example shows, in detail, how sub-typing polymorphism would
be used together with delegation, and also how type-bound procedures
with the \texttt{pass} attribute would be handled
\begin{lstlisting}[language=Fortran]
module jacobi
use interfaces, only: IRelaxationSolver, ISolver
type, implements(IRelaxationSolver) :: BlockJacobi
class(ISolver), allocatable :: blksolver
contains
procedure, pass :: driver
procedure, nopass :: relax
end type BlockJacobi
contains
subroutine driver(self,d,rhs,x)
class(BlockJacobi), intent(in) :: self
real, dimension(:,:,:,:), intent(in) :: d
real, dimension(:,:,:), intent(in) :: rhs
real, dimension(:,:,:), intent(out) :: x
call self%relax(self%blksolver,d,rhs,x)
end subroutine driver
subroutine relax(blksolver,d,rhs,x)
class(ISolver), intent(in) :: blksolver
real, dimension(:,:,:,:), intent(in) :: d
real, dimension(:,:,:), intent(in) :: rhs
real, dimension(:,:,:), intent(out) :: x
integer :: i, j
do j = 1, size(x,3)
do i = 1, size(x,2)
call blksolver%solve_system(d(:,:,i,j),rhs(:,i,j),x(:,i,j))
end do
end do
end subroutine relax
end module jacobi
\end{lstlisting}
Notice that \texttt{BlockJacobi} is an implementor (i.e. descendant)
of \texttt{IRelaxationSolver} and that therefore the above signature
of method \texttt{driver} is in accordance with its declaration in
module \texttt{interfaces}. To use \texttt{BlockJacobi}, one would
have to simply inject into it, via a constructor, an instance of
\texttt{LUDecomposition} (or any other object that implements the
\texttt{ISolver} interface) in order to intialize the allocatable,
polymorphic variable \texttt{blksolver}.
\subsection{Combination of sub-classing with sub-typing}
The new features need to be inter-operable also with type extension
(i.e. sub-classing). They need to enable one to declare derived types
that conform to some interfaces, and inherit at the same time
implementation from some other derived type, e.g. the procedure
\texttt{solve\_system} implemented by type \texttt{LUDecomposition} in
the following example:
\begin{lstlisting}[language=Fortran]
type, extends(LUDecomposition), implements(ISolver,IPrinter) :: Client
class(IPrinter), pointer :: printer => null()
contains
procedure, nopass :: print_result
end type Client
\end{lstlisting}
In the Java language, from which this idea is borrowed, the convention
is that \texttt{extends} shall precede \texttt{implements}. The
combination of sub-typing and sub-classing will allow advanced users
of the language, who have a good understanding of OO design, to employ
some advanced techniques that make use of both the flexibility that
sub-typing affords one, with the raw reduction of code lines that
sub-classing permits.
\section{Example of a use case: a Taylor series application}
To illustrate the difficulties that were discussed in
Sect.~\ref{sect:problems}, and to demonstrate how the use of the new
features will contribute to the solution of these problems, we will
present here a small case study that exhibits a pattern that is
encountered often in practical applications, namely the coupling of
two separate inheritance hierarchies through object composition. It is
truly only the pattern that is of importance here, but in order to
provide a concrete example, we will present it in the framework of a
somewhat fictional application that calculates the Taylor series
expansion of some function up to certain orders of accuracy.
\subsection{The basic design}
\label{sect:basic_design}
Suppose that we have an application that needs to calculate the Taylor
series of a function $F(x)$ for some concrete $x$ --- and it needs to
do so only up to the linear term, i.e. it only needs access to the
first derive, $F'(x)$, of $F$ with respect to $x$. Ignoring all the
details of how this first derivative might be calculated, a code
skeleton for using it within our application might look as
follows. Declare a derived type \texttt{DerivF} that contains a
procedure \texttt{deriv1} that calculates $F'(x)$, and a separate
type, named \texttt{Taylor}, that makes use of type \texttt{DerivF}
via object composition in order to \texttt{evaluate} the actual Taylor
series approximation itself (whose details, like calculation of the
zeroth order term, etc., are immaterial here):
\begin{lstlisting}[language=Fortran]
module derivs
type :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
contains
subroutine deriv1f()
write(*,*) ' 1st derivative of function F!'
end subroutine deriv1f
end module derivs
module series
use derivs, only: DerivF
type :: Taylor
type(DerivF), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
contains
subroutine term1(self)
class(Taylor), intent(in) :: self
call self%calc%deriv1()
end subroutine term1
subroutine evaluate(self)
class(Taylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
end subroutine evaluate
end module series
\end{lstlisting}
Our client application would then set up an object \texttt{teval} of
type \texttt{Taylor} in order to evaluate the Taylor series
approximation it needs, e.g. as follows
\newpage
\begin{lstlisting}[language=Fortran]
program client
use derivs, only: DerivF
use series, only: Taylor
type(Taylor), allocatable :: teval
teval = Taylor( DerivF() )
call teval%evaluate()
end program client
\end{lstlisting}
Suppose now, that our requirements on the application have changed.
We need some additional functionality. We want the application to be
able to also calculate, if required, a higher-order accurate
approximation to the Taylor series of $F$, say up to the quadratic
term. In addition, we also want it to be able to use some other
function, say $G$, instead of $F$. Moreover, we do not want to change
any of the present code structure, if possible. We only wish to extend
it by the new functionality.
\subsection{Extension by sub-classing}
\label{sect:sub-classing-example}
We will concentrate on implementing the functionality related to the
higher-order-accuracy capability first. To accomplish this, we will
use Fortran's \texttt{extends} feature for derived types
(i.e. sub-classing). We extend type \texttt{DerivF} by a child type,
\texttt{HDerivF}, that contains a procedure \texttt{deriv2} to
calculate also the higher (i.e. second) order derivative of $F$.
\begin{lstlisting}[language=Fortran]
type :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, extends(DerivF) :: HDerivF
contains
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
\end{lstlisting}
We also extend the type \texttt{Taylor} by a child type,
\texttt{HTaylor}, to deal with the evaluation of the higher order
Taylor series:
\begin{lstlisting}[language=Fortran]
type :: Taylor
type(DerivF), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type, extends(Taylor) :: HTaylor
contains
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
\end{lstlisting}
Here, we inherited method \texttt{term1} from the parent type, and
added method \texttt{term2} to enable us to calculate also the
second-order Taylor term. We also had to override the
\texttt{evaluate} method of the parent type, since the higher-order
evaluation of the complete series needs to account for this
additional, i.e. second-order, term. We have thus implemented the
skeleton of the high-order functionality, using types that make up two
separate inheritance hierarchies. However, we are still bound to
exclusive use of the function $F$. To implement the capability to use
different functions, we are going to employ the strategy pattern
\cite{Gamma_et_al_94}. We introduce a further inheritance hierarchy
made up of two new types, \texttt{DerivG}, and \texttt{HDerivG}, to
provide the same functionality for function $G$, as it was done above
for function $F$. We also need to make these hierarchies, connected to
$F$ and $G$, interchangeable, so that we can use either of them within
the code that evaluates the Taylor series. For this purpose, we
introduce the following abstract type
\begin{lstlisting}[language=Fortran]
type, abstract :: Deriv
contains
procedure(pderiv), deferred, nopass :: deriv1
end type Deriv
abstract interface
subroutine pderiv()
end subroutine pderiv
end interface
\end{lstlisting}
Now we can make both the inheritance hierarchies connected to $F$ and $G$
derive from this abstract type, and hence merge them into a single
hierarchy. Its $G$-related branch, for instance, looks as follows
\begin{lstlisting}[language=Fortran]
type, extends(Deriv) :: DerivG
contains
procedure, nopass :: deriv1 => deriv1g
end type DerivG
type, extends(DerivG) :: HDerivG
contains
procedure, nopass :: deriv2 => deriv2g
end type HDerivG
\end{lstlisting}
whereas the $F$-related branch looks completely analogous. The last
step, in implementing the strategy pattern, is to transform the variable
\texttt{calc} in type \texttt{Taylor} into a polymorphic variable of
\texttt{class(Deriv)}
\begin{lstlisting}[language=Fortran]
type :: Taylor
class(Deriv), allocatable :: calc
contains
\end{lstlisting}
in order to accept \texttt{Deriv} types from either branch of our
merged hierarchy. The complete code, that we end up with, is given
in Appendix~\ref{sect:example1}. This code\footnote{compiled
with gfortran Version 9} produces the following output
\begin{lstlisting}[language=Fortran]
Evaluating Taylor series using
1st derivative of function G!
Evaluating Taylor series using
1st derivative of function G!
2nd derivative of function G!
\end{lstlisting}
That is, the code calculates first the low-order approximation of $G$,
and subsequently its high-order approximation, as intended. It works
correctly. Yet, it is extremely bad, rigid code! The most conspicuous
symptom of its rigidity is the appearance of the \texttt{select type}
statement in the subroutine \texttt{hterm2}, that we reproduce here for
illustration:
\begin{lstlisting}[language=Fortran]
subroutine hterm2(self)
class(HTaylor), intent(in) :: self
select type ( calc => self%calc )
class is ( HDerivF )
call calc%deriv2()
class is ( HDerivG )
call calc%deriv2()
class default
write(*,*) 'Unknown type!'
end select
end subroutine hterm2
\end{lstlisting}
Obviously, this routine expects the \texttt{calc} instance to be of
either type \texttt{HDerivF} or \texttt{HDerivG}, whereas this has
been inherited from the parent type \texttt{Taylor} being of type
\texttt{class(Deriv)},
\begin{lstlisting}[language=Fortran]
type :: Taylor
class(Deriv), allocatable :: calc
contains
\end{lstlisting}
Our abstract type \texttt{Deriv} does not contain a declaration for
the method \texttt{deriv2} that the subroutine needs. Since the
compiler can't know at compile time whether at run-time \texttt{calc}
will be of the right type-extension to contain the \texttt{deriv2}
method, it will refuse to compile subroutine \texttt{hterm2} if the
\texttt{select type} statement is omitted. By coupling two inheritance
hierarchies (based on \texttt{Deriv} and \texttt{Taylor}) together, via
object composition, we have created a (potential) type conflict that
now requires a type check every time we run through the subroutine. If
we had written a real production application along these lines, that
would evaluate the Taylor series for a single scalar $x$ per call, the
type-checking would have completely killed performance!
Type extension (i.e. sub-classing) has locked us into a
straight-jacket of rigid inheritance hierarchies that denies us the
flexibility to provide our procedures with the right data types, and
has thereby forced us to circumvent the static type system of the
language, in order to get the code to work at all. But this is not the
only problem. The entire code relies on concrete derived types,
i.e. on concrete implementations. Except for type \texttt{Deriv}, it
does not use any abstractions. Should the implementation of some
concrete type need to be changed, all types that depend on it would
need to be checked and possibly changed, too, in order not to break
the program.
\subsection{Extension by sub-typing and object composition}
Now, let us go back to the point we were at at the end of
Sect.~\ref{sect:basic_design}. Let us, furthermore, suppose that Fortran
doesn't support sub-classing, and instead supports only object
composition and sub-typing (via the features proposed in
Sect.~\ref{sect:propositions}), akin to Rust or Go. We will again
focus first on the extension of our application to higher order of
accuracy. We still contemplate to introduce this functionality through
four derived types \texttt{DerivF}, \texttt{HDerivF}, \texttt{Taylor},
and \texttt{HTaylor}. But since we no longer have sub-classing at
our disposal, the only way to make these types cooperate, on solving
the task, is the following
\begin{lstlisting}[language=Fortran]
type :: Taylor
type(DerivF), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type :: HTaylor
type(HDerivF), allocatable :: calc
contains
procedure :: term1 => hterm1
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
\end{lstlisting}
that is, we need to employ object composition \emph{twice}, once in
\texttt{Taylor} and once in \texttt{HTaylor}. This is already
sufficient to avoid the appearance of a \texttt{select type} statement
in subroutine \texttt{hterm2}, because now our instance of
\texttt{calc} will be of type \texttt{HDerivF}, i.e. of the proper
type for doing high-order calculations. We will, of course, see to
it that it contains the procedure \texttt{deriv2} which calculates the
second order derivative required by the high-order Taylor series term.
The above code fragment still has a problem, though. It relies on the
concrete types \texttt{DerivF} and \texttt{HDerivF}. Our copy of
``Fortran 202y Explained'' tells us that we should rely on
abstractions instead of concretions, and depend on polymorphic
variables of abstract interfaces within our derived types, instead. We
therefore think about the functionality that these two concrete types
need to provide to their clients. We already mentioned that
\texttt{HDerivF} will have to provide an implementation of subroutine
\texttt{deriv2}. However, and as it was the case in
Sect.~\ref{sect:sub-classing-example}, \texttt{HDerivF} also needs to
implement procedure \texttt{deriv1}, while \texttt{DerivF} needs to
implement \emph{only} the latter procedure. Hence, we distill the
signatures of these methods into two abstract interfaces
\begin{lstlisting}[language=Fortran]
abstract interface :: IDeriv
subroutine deriv1()
end subroutine deriv1
end interface IDeriv
abstract interface, extends(IDeriv) :: IHDeriv
subroutine deriv2()
end subroutine deriv2
end interface IHDeriv
\end{lstlisting}
and then make use of these interfaces to modify our code for the
Taylor types as follows
\begin{lstlisting}[language=Fortran]
type :: Taylor
class(IDeriv), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type :: HTaylor
class(IHDeriv), allocatable :: calc
contains
procedure :: term1 => hterm1
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
\end{lstlisting}
With this single stroke, we have just solved our entire problem,
including the requirement of being able to calculate the Taylor series
of different functions! Moreover, we have accomplished this goal with
ease. The only things that remain to be done are to make
\texttt{DerivF} and \texttt{HDerivF} simply implement the two abstract
interfaces, e.g. as follows
\begin{lstlisting}[language=Fortran,
caption={Implementation of interfaces for derivatives of function $F$.},
label={listing:implderivf}]
type, implements(IDeriv) :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, implements(IHDeriv) :: HDerivF
contains
procedure, nopass :: deriv1 => deriv1f
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
\end{lstlisting}
and to add two more types, \texttt{DerivG}, and \texttt{HDerivG}, in
exactly the same fashion, in order to provide implementations of the
same functionality for function $G$.
We are finished! Since both \texttt{DerivF} and \texttt{DerivG} now
conform to the abstract \texttt{IDeriv} interface, we can easily swap
instances of either of them into type \texttt{Taylor} at will, in
order to calculate the Taylor series of either $F$ or $G$. Similar
functionality is exhibited by the types that implement the high-order
series. We didn't even have to spend a single thought on using the
strategy pattern for these purposes. We used it naturally without
thinking about it because it was encouraged by the features contained
in the language.
The complete code, that uses this sub-typing approach, is given in
Appendix~\ref{sect:example2}. It is an almost literal translation of a
Java as well as a Rust code, that were used to test and verify the
presented ideas. The code in Appendix~\ref{sect:example2} is vastly
superior compared to the one that uses sub-classing and is given in
Appendix~\ref{sect:example1}. Both codes have roughly the same number
of lines, but in the one relying on sub-typing there are \emph{no}
\texttt{select type} statements, \emph{no} sub-classing hierarchies,
and \emph{no} dependencies on concrete types. We have inverted all the
dependencies in the algorithm, i.e. the only dependencies are on
abstract interfaces. We have thus attained the highest possible degree
of decoupling. The \emph{only} part of the code that depends on
concrete types is the main client program, whose sole purpose is to
organize the entire process of injecting instances of the correct
concrete types via (Fortran default) constructors into the lower level
code.
This decoupling of types leads to multiple benefits. For instance (and
provided we have compiled the \texttt{interfaces} module), we gain the
freedom to compile the \texttt{derivs} and \texttt{series} modules in
any order we like, even in parallel if we wish to. We thereby
neutralized the biggest drawback of a module system (like Fortran's)
for separate compilation, namely serialization of the compilation
process. We also avoid re-compilation cascades in case we need to
change the implementation of some concrete type, as long as we leave
its (abstract) interface intact. We are, moreover, free to take any of
the aforementioned modules and reuse it in another application,
without having to drag along numerous dependencies. In summary, using
the new features we have not only accomplished to make the code more
efficient, but also much more flexible, much more maintainable, and
much more reusable.
\subsection{Combination of the two inheritance types}
The code given in Appendix~\ref{sect:example2} strictly conforms to
the dependency inversion principle. By relaxing this requirement, and
allowing for the use of both sub-typing and sub-classing, we could
have written the code fragment in Listing~\ref{listing:implderivf}
above somewhat more concise as
\begin{lstlisting}[language=Fortran]
type, implements(IDeriv) :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, extends(DerivF), implements(IHDeriv) :: HDerivF
contains
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
\end{lstlisting}
This saves us the labor of providing an implementation for procedure
\texttt{deriv1} within type \texttt{HDerivF}, at the significant cost
of \texttt{HDerivF} depending now on a concretion, i.e. on type
\texttt{DerivF}. In this particular, trivial, example, we have only
saved a single line of code in this way. But had \texttt{DerivF}
contained half a dozen or so methods, which we would have been forced
to implement also in \texttt{HDerivF}, the convenience that the
combination of \texttt{extends} and \texttt{implements} would have
afforded us for reducing the number of code-lines could hardly have
been passed up.
\subsection{Summary}
The features proposed in this document would significantly enhance
Fortran's OOP capabilities without affecting backwards compatibility.
Moreover, Fortran compilers that adhere to at least the Fortran 2003
standard could implement them relatively easily, as most of the
functionality required to support them is already present in some form
in such compilers for the support of sub-classing, i.e. the extension
of derived types.
\bibliographystyle{plain}
\bibliography{Fortran_OOP}
\lstdefinestyle{mystyle}{
% backgroundcolor=\color{backcolour},
commentstyle=\color{codegreen},
% keywordstyle=\color{magenta},
numberstyle=\tiny\color{codegray},
stringstyle=\color{codepurple},
basicstyle=\ttfamily\footnotesize,
breakatwhitespace=false,
breaklines=true,
captionpos=b,
keepspaces=true,
numbers=left,
numbersep=5pt,
showspaces=false,
showstringspaces=false,
showtabs=false,
tabsize=2
}
\lstset{style=mystyle}
\begin{appendices}
\section{Taylor series example based on sub-classing}
\label{sect:example1}
\begin{lstlisting}[language=Fortran]
module derivs
type, abstract :: Deriv
contains
procedure(pderiv), deferred, nopass :: deriv1
end type Deriv
abstract interface
subroutine pderiv()
end subroutine pderiv
end interface
type, extends(Deriv) :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, extends(DerivF) :: HDerivF
contains
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
type, extends(Deriv) :: DerivG
contains
procedure, nopass :: deriv1 => deriv1g
end type DerivG
type, extends(DerivG) :: HDerivG
contains
procedure, nopass :: deriv2 => deriv2g
end type HDerivG
contains
subroutine deriv1f()
write(*,*) ' 1st derivative of function F!'
end subroutine deriv1f
subroutine deriv2f()
write(*,*) ' 2nd derivative of function F!'
end subroutine deriv2f
subroutine deriv1g()
write(*,*) ' 1st derivative of function G!'
end subroutine deriv1g
subroutine deriv2g()
write(*,*) ' 2nd derivative of function G!'
end subroutine deriv2g
end module derivs
module series
use derivs, only: Deriv, HDerivF, HDerivG
type :: Taylor
class(Deriv), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type, extends(Taylor) :: HTaylor
contains
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
contains
subroutine term1(self)
class(Taylor), intent(in) :: self
call self%calc%deriv1()
end subroutine term1
subroutine evaluate(self)
class(Taylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
end subroutine evaluate
subroutine hterm2(self)
class(HTaylor), intent(in) :: self
select type ( calc => self%calc )
class is ( HDerivF )
call calc%deriv2()
class is ( HDerivG )
call calc%deriv2()
class default
write(*,*) 'Unknown type!'
end select
end subroutine hterm2
subroutine hevaluate(self)
class(HTaylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
call self%term2()
end subroutine hevaluate
end module series
program client
use derivs, only: DerivG, HDerivG, Deriv
use series, only: Taylor, HTaylor
class(Deriv), allocatable :: derv
class(Taylor), allocatable :: teval
derv = DerivG()
teval = Taylor(derv)
call teval%evaluate()
write(*,*)
derv = HDerivG()
teval = HTaylor(derv)
call teval%evaluate()
end program client
\end{lstlisting}
\section{Taylor series example based on sub-typing}
\label{sect:example2}
\begin{lstlisting}[language=Fortran]
module interfaces
abstract interface :: IDeriv
subroutine deriv1()
end subroutine deriv1
end interface IDeriv
abstract interface, extends(IDeriv) :: IHDeriv
subroutine deriv2()
end subroutine deriv2
end interface IHDeriv
end module interfaces
module derivs
use interfaces, only: IDeriv, IHDeriv
type, implements(IDeriv) :: DerivF
contains
procedure, nopass :: deriv1 => deriv1f
end type DerivF
type, implements(IHDeriv) :: HDerivF
contains
procedure, nopass :: deriv1 => deriv1f
procedure, nopass :: deriv2 => deriv2f
end type HDerivF
type, implements(IDeriv) :: DerivG
contains
procedure, nopass :: deriv1 => deriv1g
end type DerivG
type, implements(IHDeriv) :: HDerivG
contains
procedure, nopass :: deriv1 => deriv1g
procedure, nopass :: deriv2 => deriv2g
end type HDerivG
contains
subroutine deriv1f()
write(*,*) " 1st derivative of function F!"
end subroutine deriv1f
subroutine deriv2f()
write(*,*) " 2nd derivative of function F!"
end subroutine deriv2f
subroutine deriv1g()
write(*,*) " 1st derivative of function G!"
end subroutine deriv1g
subroutine deriv2g()
write(*,*) " 2nd derivative of function G!"
end subroutine deriv2g
end module derivs
module series
use interfaces, only: IDeriv, IHDeriv
type :: Taylor
class(IDeriv), allocatable :: calc
contains
procedure :: term1
procedure :: evaluate
end type Taylor
type :: HTaylor
class(IHDeriv), allocatable :: calc
contains
procedure :: term1 => hterm1
procedure :: term2 => hterm2
procedure :: evaluate => hevaluate
end type HTaylor
contains
subroutine term1(self)
class(Taylor), intent(in) :: self
call self%calc%deriv1()
end subroutine term1
subroutine evaluate(self)
class(Taylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
end subroutine evaluate
subroutine hterm1(self)
class(HTaylor), intent(in) :: self
call self%calc%deriv1()
end subroutine hterm1
subroutine hterm2(self)
class(HTaylor), intent(in) :: self
call self%calc%deriv2()
end subroutine hterm2
subroutine hevaluate(self)
class(HTaylor), intent(in) :: self
write(*,*) 'Evaluating Taylor series using'
call self%term1()
call self%term2()
end subroutine hevaluate
end module series
program client
use derivs, only: DerivG, HDerivG
use series, only: Taylor, HTaylor
type(Taylor), allocatable :: teval
type(HTaylor), allocatable :: hteval
teval = Taylor( DerivG() )
call teval%evaluate()
write(*,*)
hteval = HTaylor( HDerivG() )
call hteval%evaluate()
end program client
\end{lstlisting}
\end{appendices}
\end{document}
================================================
FILE: proposals/traits/20-109.txt
================================================
To: J3 J3/20-109
From: Brad Richardson
Subject: Traits for Types
Date: 2020-February-23
Proposal for Fortran Standard: 202y (NOT 202x)
1. Problem
Currently, in order to pass a derived type to some library expected a type
derived from it's own abstract type requires the addition of a "wrapper"
type to be used. This requires a cumbersome amount of boiler plate code and
is not conducive to the type of "generic" code one would like to be able to
write.
This proposal seeks to address the issue that writing "generic" libraries
is either not possible, or places undue burden on its users. The main
benefits are the reduction in repeated logic or boiler plate wrapper types
required for generic libraries, thereby enabling more code reuse and easier
to maintain code bases.
2. Proposed Solution
The solution would require the addition of a few attributes and variable
declaration capabilities. First is the addition of the `trait` attribute to
a type specification. This requires that the type be abstract, and contain
no components. I.e.
type, abstract, trait :: Show_t
contains
procedure(show_i), deferred :: show
end type Show_t
abstract interface
function show_i(self) result(string)
class(Show_t), intent(in) :: self
character(len=:), allocatable :: string
end function show_i
end interface
Second is the addition of the `implements` attribute for a type
specification. The `implements` attribute requires a list of at least one
trait the type is to implement, requiring the type to contain the
procedures with the interfaces defined by the trait(s). I.e.
type, implements(Show_t) :: Thing_t
character(len=:), allocatable :: the_string
contains
procedure :: show
end type Thing_t
function show(self) result(string)
class(Thing_t), intent(in) :: self
character(len=:), allocatable :: string
string = self%the_string
end function show
Third is the addition of a variable declaration form using `trait`, in a
similar fashion to `class`. The `trait` specification would require a list
of at least one trait, and must either be allocatable, or a dummy argument
of a procedure. In a similar manner that the instantiated value of a class
variable must be of that type, or an extended type, the instantiated value
of a trait variable must be of a type which implements the given trait(s).
Thus, no components of the instantiated value are accessible, only the
procedures defined by the trait(s).
3. Backward compatibility
This addition to the language would not break any existing standard
conforming Fortran program, and thus preserves Fortran's backward
compatibility.
4. Further discussion
Online discussion that led to this proposal can be found at
https://github.com/j3-fortran/fortran_proposals/issues/125
================================================
FILE: proposals/worklist/26-116-din3a-recommend.txt
================================================
To: J3 J3/26-116
From: HPC
Subject: Recommendation for DIN3a "Support atomic operations in local memory"
Date: 2026-February-11
References: 24-167, WG5/N2230, WG5/N2234, WG5/N2249
1. Background
=============
WG5/N2249 provides the list of accepted work items for the next revision of
ISO/IEC 1539:2023 (Fortran 202Y). That list currently includes accepted work
item:
- DIN3a Add support for atomic operations in local memory
Ref: N2230 "DIN Suggestions for F202Y" (other features requested
in DIN3 were not accepted.)
This work item was initially added to the list by WG5 at the June 2024 meeting
in WG5/N2234. As indicated above, it comprises a small subset of the broader
item DIN3 proposed in WG5/N2230 (and subsequently mostly declined by WG5) to
expand support for APU processing. The remaining subset relevant to atomic
operations amounts to a two-sentence request with no specific rationale or use
cases. To our knowledge, no follow-up J3 papers have been published to further
support work item DIN3a or elaborate a proposed design for this feature in
isolation. Nevertheless, Info paper 24-167 rated item DIN3a with difficulty
level 5 ("Technical change likely to need more than two J3 meetings to
develop").
In June 2025, WG5 voted to remove the proposed asynchronous tasking feature
from Fortran 202Y work list item US04. With the deferral of asynchronous
tasking, it's even less clear how the underspecified DIN3a work item is
motivated to fit into the remaining language features in Fortran 202Y.
2. Subgroup Recommendation
==========================
The J3 HPC subgroup recommends that item DIN3a be removed (without prejudice)
from the Fortran 202Y work list. Proponents are welcome to resubmit the feature
request for a future revision, along with a more substantive rationale and
design sketch.
3. Resolution
=============
In passing this paper, INCITS/Fortran (J3) recommends to WG5 that item DIN3a be
removed from the work list for Fortran 202Y.
===END===
gitextract_o6bns626/
├── CODE_OF_CONDUCT.md
├── README.md
├── augmented_assignment/
│ └── augmented_assignment.txt
├── proposal-template.txt
└── proposals/
├── assert/
│ └── design_by_contract.txt
├── c23_interop/
│ ├── 26-112.txt
│ └── 26-122.txt
├── cmplx-real-pointers.txt
├── conditional_expressions/
│ └── 21-165.txt
├── default_optional_arguments/
│ └── proposal.txt
├── fp_interop/
│ ├── 25-189r1.txt
│ ├── 25-203.txt
│ └── 25-203r1.txt
├── namelist_delimiters/
│ └── namelist_proposal.txt
├── namespace_modules/
│ ├── 19-246.txt
│ └── 20-108.txt
├── protected_attribute.txt
├── run-time_polymorphism/
│ ├── Examples/
│ │ ├── AppendixA/
│ │ │ └── taylor.f90
│ │ ├── AppendixB/
│ │ │ ├── taylor.f90
│ │ │ ├── taylor.java
│ │ │ └── taylor.rs
│ │ └── Text/
│ │ └── taylor_basic.f90
│ ├── Fortran_OOP.bib
│ └── Fortran_OOP.tex
├── traits/
│ └── 20-109.txt
└── worklist/
└── 26-116-din3a-recommend.txt
SYMBOL INDEX (48 symbols across 2 files)
FILE: proposals/run-time_polymorphism/Examples/AppendixB/taylor.java
type IDeriv (line 6) | interface IDeriv {
method deriv1 (line 7) | void deriv1();
type IHDeriv (line 10) | interface IHDeriv extends IDeriv {
method deriv2 (line 11) | void deriv2();
class DerivF (line 14) | class DerivF implements IDeriv {
method deriv1 (line 15) | public void deriv1() {
class HDerivF (line 20) | class HDerivF implements IHDeriv {
method deriv1 (line 21) | public void deriv1() {
method deriv2 (line 24) | public void deriv2() {
class DerivG (line 29) | class DerivG implements IDeriv {
method deriv1 (line 30) | public void deriv1() {
class HDerivG (line 35) | class HDerivG implements IHDeriv {
method deriv1 (line 36) | public void deriv1() {
method deriv2 (line 39) | public void deriv2() {
class Taylor (line 44) | class Taylor {
method Taylor (line 46) | Taylor(IDeriv calculator) {
method term1 (line 49) | public void term1() {
method evaluate (line 52) | public void evaluate() {
class HTaylor (line 58) | class HTaylor {
method HTaylor (line 60) | HTaylor(IHDeriv calculator) {
method term1 (line 63) | public void term1() {
method term2 (line 66) | public void term2() {
method evaluate (line 69) | public void evaluate() {
class ClientApp (line 76) | class ClientApp {
method main (line 78) | public static void main(String[] args) {
FILE: proposals/run-time_polymorphism/Examples/AppendixB/taylor.rs
type IDeriv (line 8) | pub trait IDeriv {
method deriv1 (line 9) | fn deriv1(&self);
method deriv1 (line 26) | fn deriv1(&self) {
method deriv1 (line 45) | fn deriv1(&self) {
type IHDeriv (line 12) | pub trait IHDeriv {
method deriv1 (line 13) | fn deriv1(&self);
method deriv2 (line 14) | fn deriv2(&self);
method deriv1 (line 34) | fn deriv1(&self) {
method deriv2 (line 37) | fn deriv2(&self) {
method deriv1 (line 53) | fn deriv1(&self) {
method deriv2 (line 56) | fn deriv2(&self) {
type DerivF (line 23) | pub struct DerivF {
type HDerivF (line 31) | pub struct HDerivF {
type DerivG (line 42) | pub struct DerivG {
type HDerivG (line 50) | pub struct HDerivG {
type Taylor (line 67) | pub struct Taylor {
method term1 (line 71) | pub fn term1(&self) {
method evaluate (line 74) | pub fn evaluate(&self) {
type HTaylor (line 80) | pub struct HTaylor {
method term1 (line 84) | pub fn term1(&self) {
method term2 (line 87) | pub fn term2(&self) {
method evaluate (line 90) | pub fn evaluate(&self) {
function main (line 98) | fn main() {
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (167K chars).
[
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3257,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "README.md",
"chars": 2682,
"preview": "# Fortran Proposals\n\nThis repository contains proposals for the Fortran Standard Committee in the [Issues](https://githu"
},
{
"path": "augmented_assignment/augmented_assignment.txt",
"chars": 2978,
"preview": "To: J3 J3/XX-XXX\nFrom: Leonard Reuter \nSubject: Augmented Assignment"
},
{
"path": "proposal-template.txt",
"chars": 105,
"preview": "To: J3 J3/XX-XXX\nFrom: \nSubject: \nDate: \n#Reference:\n"
},
{
"path": "proposals/assert/design_by_contract.txt",
"chars": 9910,
"preview": "To: J3 J3/XX-XXX\nFrom: William B. Clodius\nSubject: Facilitate design"
},
{
"path": "proposals/c23_interop/26-112.txt",
"chars": 8537,
"preview": "To: J3 J3/26-112\nFrom: Patrick Fasano\nSubject: Edits for updating re"
},
{
"path": "proposals/c23_interop/26-122.txt",
"chars": 8932,
"preview": "To: J3 J3/26-122\nFrom: Patrick Fasano & HPC\nSubject: Reqs/specs for "
},
{
"path": "proposals/cmplx-real-pointers.txt",
"chars": 9154,
"preview": "To: J3 J3/24-129\nFrom: Pierre Hugonnet\nSubject: allow complex pointe"
},
{
"path": "proposals/conditional_expressions/21-165.txt",
"chars": 2049,
"preview": "To: J3 J3/21-165\nFrom: Ondrej Certik, Milan Curcic, Zach Jibben\nSubj"
},
{
"path": "proposals/default_optional_arguments/proposal.txt",
"chars": 9985,
"preview": "To: J3 J3/XX-XXX\nFrom: Milan Curcic, Jeremie Vandenplas, Zach Jibben"
},
{
"path": "proposals/fp_interop/25-189r1.txt",
"chars": 6937,
"preview": "To: J3 J3/25-189r1\nFrom: Patrick Fasano\nSubject: Requirements and sp"
},
{
"path": "proposals/fp_interop/25-203.txt",
"chars": 6937,
"preview": "To: J3 J3/25-203\nFrom: Patrick Fasano\nSubject: US05: Edits for C int"
},
{
"path": "proposals/fp_interop/25-203r1.txt",
"chars": 7008,
"preview": "To: J3 J3/25-203r1\nFrom: Patrick Fasano\nSubject: US05: Edits for C i"
},
{
"path": "proposals/namelist_delimiters/namelist_proposal.txt",
"chars": 6816,
"preview": "To: J3 J3/XX-XXX\nFrom: Marshall Ward\nSubject: Require delimiters for"
},
{
"path": "proposals/namespace_modules/19-246.txt",
"chars": 3123,
"preview": "To: J3 J3/19-246\nFrom: Ondrej Certik\nSubject: Namespace For Modules\n"
},
{
"path": "proposals/namespace_modules/20-108.txt",
"chars": 3264,
"preview": "To: J3 J3/20-108\nFrom: Ondrej Certik\nSubject: Namespace For Modules\n"
},
{
"path": "proposals/protected_attribute.txt",
"chars": 3373,
"preview": "To: J3 J3/##-###\nFrom: Balint Aradi\nSubject: Protected attribute for"
},
{
"path": "proposals/run-time_polymorphism/Examples/AppendixA/taylor.f90",
"chars": 2848,
"preview": "! Fortran implementation of the Taylor series example program based on\n! subclassing given in Appendix A of the proposal"
},
{
"path": "proposals/run-time_polymorphism/Examples/AppendixB/taylor.f90",
"chars": 3062,
"preview": "! Fortran implementation of the Taylor series example program based on\n! subtyping given in Appendix B of the proposal \""
},
{
"path": "proposals/run-time_polymorphism/Examples/AppendixB/taylor.java",
"chars": 1749,
"preview": "// Java implementation of the Taylor series example program based on\n// subtyping given in Appendix B of the proposal \"I"
},
{
"path": "proposals/run-time_polymorphism/Examples/AppendixB/taylor.rs",
"chars": 2344,
"preview": "// Rust implementation of the Taylor series example program based on\n// subtyping given in Appendix B of the proposal \"I"
},
{
"path": "proposals/run-time_polymorphism/Examples/Text/taylor_basic.f90",
"chars": 928,
"preview": "module derivs\n type :: DerivF\n contains\n procedure, nopass :: deriv1 => deriv1f\n end type DerivF\ncontains\n "
},
{
"path": "proposals/run-time_polymorphism/Fortran_OOP.bib",
"chars": 1343,
"preview": "@INPROCEEDINGS{Snyder86,\n author = {Alan Snyder},\n title = {Encapsulation and Inheritance in Object-Oriented\n "
},
{
"path": "proposals/run-time_polymorphism/Fortran_OOP.tex",
"chars": 47249,
"preview": "\\documentclass[11pt,oneside]{article}\n\\usepackage[a4paper, total={6.5in, 9in}]{geometry}\n\\usepackage{natbib}\n\\usepackage"
},
{
"path": "proposals/traits/20-109.txt",
"chars": 2882,
"preview": "To: J3 J3/20-109\nFrom: Brad Richardson\nSubject: Traits for Types\nDat"
},
{
"path": "proposals/worklist/26-116-din3a-recommend.txt",
"chars": 2059,
"preview": "To: J3 J3/26-116\nFrom: HPC\nSubject: Recommendation for DIN3a \"Suppor"
}
]
About this extraction
This page contains the full source code of the j3-fortran/fortran_proposals GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (155.8 KB), approximately 40.6k tokens, and a symbol index with 48 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.