# Trick for optional arguments with defaults

**URL:** <https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852>\
**Category:** Uncategorized\
**Created:** [April 13, 2026, 11:15am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852 "2026-04-13T11:15:11Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [April 13, 2026, 11:15am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/1 "2026-04-13T11:15:11Z")

</div>

It’s very common when dealing with optional arguments to have a local variable that is assigned either a default value or the value of a present argument, like:

```auto
subroutine bar(...,a)
    real, intent(in), optional :: a
    real :: a_local
    a_local = 2.0; if (present(a)) a_local = a
    ... ! use only a_local in the further code
end subroutine

```

And it’s also very common to use the argument `a` by mistake instead of `a_local`, resulting in a segmentation violation during execution if `a` was not present.

A way to prevent such an error is to use an ASSOCIATE block that spans the whole routine:

```auto
subroutine bar(...,a)
    real, intent(in), optional :: a
    real :: a_local
    a_local = 2.0; if (present(a)) a_local = a
    ASSOCIATE( a => a_local )
    ... ! "a" can now be safely used as an alias to a_local
    END ASSOCIATE
end subroutine

```

The dummy argument `a` is shadowed by the alias `a` inside the block. Another benefit is that we don’t have to use the local variable name with a somehow artificial suffix (`_local` or whatever)

---

<div class="post-metadata">

**Author:** ![tyranids](https://avatars.discourse-cdn.com/v4/letter/t/3e96dc/32.png) [@tyranids](https://fortran-lang.discourse.group/u/tyranids)\
**Post date:** [April 13, 2026, 12:34pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/2 "2026-04-13T12:34:23Z")

</div>

I only just started using `block`…`end block` in things like loops to declare local variables and such in a smaller scope.

Can you nest these structures? Meaning can you have multiple associate or block constructs within each other?

---

<div class="post-metadata">

**Author:** ![jwmwalrus](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jwmwalrus/32/4483_2.png) [@jwmwalrus](https://fortran-lang.discourse.group/u/jwmwalrus)\
**Post date:** [April 13, 2026, 1:03pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/3 "2026-04-13T13:03:26Z")

</div>

In theory, you can have as many nested `associate` and `block` constructs as you want.

In practice:

The `associate-construct` is a thin pseudo-scope (the underlying behavior is that of pointers and shadowing), so you could nest as many as you want… until it starts getting confusing.

The `block-construct`, on the other hand, is a true scope, so it’s bound by the stack’s limits (and recursion complicates things).

Both constructs are also bound by the compiler’s rules (e.g., for `ifort`, I think the magic nesting number was 31, all constructs combined).

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [April 13, 2026, 2:01pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/4 "2026-04-13T14:01:07Z")

</div>

We also created the [optval](https://stdlib.fortran-lang.org/page/specs/stdlib_optval.html) function in stdlib exactly for this purpose.

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [April 13, 2026, 2:25pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/5 "2026-04-13T14:25:38Z")

</div>

The two approaches are actually complementary. `optval()` is fine as long as the argument is used once or twice. If repeatedly used it will tend to be less readable than a local variable (and a change of the default value requires several changes in the code).

They can also be combined (not tested, but should work):

```auto
ASSOCIATE( a => optval( a, 2.0 ) )

```

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [April 13, 2026, 5:21pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/6 "2026-04-13T17:21:57Z")

</div>

> [@tyranids](#):
>
> Can you nest these structures? Meaning can you have multiple associate or block constructs within each other?

ASSOCIATE blocks work, more or less, like invoking a contained procedure with actual arguments being associated with the contained procedure dummy arguments. However, one difference is that ASSOCIATE blocks are allowed to be nested arbitrarily by the standard (at least to some compiler limit), while CONTAINS is limited to only one level (or two, if you count the CONTAINS statement in a module). A programmer runs into that CONTAINS limit when converting statement functions in legacy codes to contained procedures within a module. That limit has always annoyed me, I guess for being so arbitrary and seemingly unnecessary. You can usually work around the problem by flattening the hierarchy, but it sometimes requires renaming the functions to avoid conflicts.

---

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [April 13, 2026, 5:28pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/7 "2026-04-13T17:28:07Z")

</div>

My [Pure-Fortran](https://github.com/Beliavsky/Pure-Fortran) project has a script to warn about the unsafe use of optional arguments. For the code

```fortran
module m
implicit none
contains
function max2(x1, x2) result(xmax)
real, intent(in) :: x1
real, intent(in), optional :: x2
real :: xmax
if (present(x2)) then
   xmax = max(x1, x2)
else
   xmax = x1
end if
end function max2

function max_(x1, x2, x3, x4, x5) result(xmax)
real, intent(in) :: x1, x2
real, optional, intent(in) :: x3, x4, x5
real :: xmax
xmax = max(x1, x2)
if (present(x3)) xmax = max(x3, xmax)
xmax = max2(xmax, x4) ! allowed since 2nd argument of max2 is OPTIONAL
xmax = max(xmax, x5) ! unsafe since x5 may not be PRESENT
end function max_
end module m

use m
print*,max_(3.2, 2.6)
print*,max_(3.2, 2.6, 4.5)
end

```

`python xoptional.py xoptional.f90` gives

```auto
1 optional-argument guard finding(s) in 1 file(s) (definite 1, possible 0).
xoptional.f90: 1

First finding: xoptional.f90:22 function max_ x5 [definite] - optional argument may be used without guaranteed PRESENT() guard

```

---

<div class="post-metadata">

**Author:** ![Machalot](https://avatars.discourse-cdn.com/v4/letter/m/ebca7d/32.png) [@Machalot](https://fortran-lang.discourse.group/u/Machalot)\
**Post date:** [April 13, 2026, 7:51pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/8 "2026-04-13T19:51:05Z")

</div>

In the 2023 standard could this be handled like so?

```fortran
a = (present(a) ? a : a_default)

```

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [April 13, 2026, 7:56pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/9 "2026-04-13T19:56:49Z")

</div>

> [@Beliavsky](#):
>
> ```auto
> xmax = max(xmax, x5) ! unsafe since x5 may not be PRESENT
> end function max_
> 
> ```

I agree, but this leads to the question of whether

```auto
xmax = max( x1, x2, x5 )

```

is safe. Even though the arguments 3 and beyond are optional in the syntax of the `max()` intrinsic, they are not optional arguments in the formal sense, so I think the answer is that this is also unsafe. It seems that all of the arguments to the intrinsic `max()` function are required to be present.

---

<div class="post-metadata">

**Author:** ![hkvzjal](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/hkvzjal/32/3055_2.png) [@hkvzjal](https://fortran-lang.discourse.group/u/hkvzjal)\
**Post date:** [April 13, 2026, 8:59pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/10 "2026-04-13T20:59:03Z")

</div>

> [@PierU](#):
>
> A way to prevent such an error is to use an ASSOCIATE block that spans the whole routine:
> 
> ```auto
> subroutine bar(...,a)
> real, intent(in), optional :: a
> real :: a_local
> a_local = 2.0; if (present(a)) a_local = a
> ASSOCIATE( a => a_local )
> ... ! "a" can now be safely used as an alias to a_local
> END ASSOCIATE
> end subroutine
> 
> ```

Be wary though of possible performance penalties that can be unadvertely introduced due to the way some compilers interpret `associate` [Fortran skill markdown for codex - #22 by ivanpribec](https://fortran-lang.discourse.group/t/fortran-skill-markdown-for-codex/10783/22) it probably won’t be an issue for scalar optionals but it could if the optional is an array.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [April 13, 2026, 10:07pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/11 "2026-04-13T22:07:08Z")

</div>

> [@Machalot](#):
>
> `a = (present(a) ? a : a_default)`

I think this is unsafe. The expression on the rhs is safe, but if `a` is not present, then this would be an assignment to that argument.

---

<div class="post-metadata">

**Author:** ![Machalot](https://avatars.discourse-cdn.com/v4/letter/m/ebca7d/32.png) [@Machalot](https://fortran-lang.discourse.group/u/Machalot)\
**Post date:** [April 14, 2026, 12:40am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/12 "2026-04-14T00:40:36Z")

</div>

Then I suppose this would be better:

```fortran
a = (present(a_in) ? a_in : a_default)

```

where `a_in` is the name of the optional argument and `a` is a local variable.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [April 14, 2026, 3:18am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/13 "2026-04-14T03:18:04Z")

</div>

> [@Machalot](#):
>
> where `a_in` is the name of the optional argument and `a` is a local variable.

This is kind of a trivial issue, but here is the problem with this.

Fortran subroutines can be called with positional arguments, keyword arguments, or a combination of both. When you use keyword arguments, you want the dummy argument names to be as descriptive and mnemonic as possible. This makes adding suffixes such as ‘\_in’ to otherwise meaningful dummy argument names unsatisfactory.

On the other hand, as was pointed out, if the good variable names are used for the dummy arguments, then the weird names with the ‘\_local’ suffix need to be used internally.

The ASSOCIATE approach allows the local name and the dummy argument name to be the same, but it does have some restrictions (i.e. some attributes such as `allocatable` no longer apply).

---

<div class="post-metadata">

**Author:** ![urbanjost](https://avatars.discourse-cdn.com/v4/letter/u/0ea827/32.png) [@urbanjost](https://fortran-lang.discourse.group/u/urbanjost)\
**Post date:** [April 14, 2026, 7:17am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/14 "2026-04-14T07:17:26Z")

</div>

Hmm. Particularly with an intent(in) argument would this work? I am not using a compiiler that has the condition?true:false syntax. Normally I would avoid using the  
same name for an associate-name and a variable in the parent scope (to the point I have never tried it) but in this case it might be appropriate is this would work?

```fortran
program testit
   call one(987654321)
contains
   subroutine one(a)
      integer,intent(in) :: a
      associate (a => (present(a) ? a : 100) )
         write(*,*)a
      end associate
   end subroutine one
end program testit

```

This appears to work (just pretend using stdlib and so optval is already available):

```fortran
program testit

   call one(87654321)
   call one()

contains

subroutine one(A)
integer,intent(in),optional :: A
associate (A => optval_i(A,100) )
   write(*,*)A
end associate
end subroutine one

pure elemental function optval_i(x, default) result(y)
integer, intent(in), optional :: x
integer, intent(in) :: default
integer :: y

   if (present(x)) then
      y = x
   else
      y = default
   endif

end function optval_i

end program testit

```

### Output

```plaintext
    87654321
         100

```

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [April 14, 2026, 10:49am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/15 "2026-04-14T10:49:12Z")

</div>

`VALUE` to the rescue.

---

<div class="post-metadata">

**Author:** ![wspector](https://avatars.discourse-cdn.com/v4/letter/w/47e85d/32.png) [@wspector](https://fortran-lang.discourse.group/u/wspector)\
**Post date:** [April 14, 2026, 5:00pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/16 "2026-04-14T17:00:53Z")

</div>

> [@urbanjost](#):
>
> I am not using a compiiler that has the condition?true:false syntax.

This F2023 feature was implemented in gfortran in the latter part of 2025. So if you build a current snapshot, it’s there. Works very nicely. Not sure what other compilers support it yet.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [April 14, 2026, 5:48pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/17 "2026-04-14T17:48:27Z")

</div>

> [@themos](#):
>
> `VALUE` to the rescue.

I think I’m not doing the right incantation.

```auto
program foo
   call bar(42)
   call bar()
contains
   subroutine bar(a)
      integer, value, optional :: a
      if ( .not. present(a) ) a = 100
      write(*,*) 'present(a)=', present(a), 'a=', a
   end subroutine bar
end program foo

```

This works with gfortran, but not with flang.

```auto
$ flang --version foo.f90 && a.out
Homebrew flang version 22.1.3
Target: arm64-apple-darwin25.4.0
Thread model: posix
InstalledDir: /opt/homebrew/Cellar/flang/22.1.3/libexec
Configuration file: /opt/homebrew/Cellar/flang/22.1.3/libexec/flang.cfg
Configuration file: /opt/homebrew/Cellar/flang/22.1.3/etc/clang/arm64-apple-darwin25.cfg
 present(a)= T a= 42
Segmentation fault: 11

```

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [April 14, 2026, 6:11pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/18 "2026-04-14T18:11:27Z")

</div>

ifx 2025.3 and nvfortran 26.1 also segfault: [Compiler Explorer](https://godbolt.org/z/vba73jdb8)

Goes to show that Fortran programmers don’t make use of the `VALUE, OPTIONAL` attribute pair very often…

NAG Fortran:

```txt
> nagfor test_optional.f90 && ./a.out
NAG Fortran Compiler Release 7.2(Shin-Urayasu) Build 7203
[NAG Fortran Compiler normal termination]
 present(a)= T a= 42
 present(a)= F a= 100

```

LFortran (version 0.50 and higher) works too! Proof: [Compiler Explorer](https://godbolt.org/z/4PTTTTjsz)

Cray Fortran v20:

```txt
$ crayftn -O0 test_optional.f90 && ./a.out
 present(a)= T a= 42
Segmentation fault (core dumped)

```

With higher optimization levels it just skips the second `bar` call…

```txt
$ crayftn -O2 test_optional.f90 && ./a.out
 present(a)= T a= 42

```

* * *

I wonder what happens if `bind(C)` is added; should be illegal IMO. I just gave it a try:

> **Compiler results**
>
> Cray Fortran:
> 
> ```tyt
> ftn-630 ftn: ERROR BAR, File = test_optional.f90, Line = 5, Column = 19
> Object "A", a dummy argument to a BIND(C) routine must not have both the value and optional attributes.
> 
> ```
> 
> LFortran:
> 
> ```txt
> code generation error: asr_to_llvm: module failed verification. Error:
> Store operand must be a pointer.
> store i32 100, i32 %a, align 4
> 
> ```
> 
> gfortran:
> 
> ```txt
> Error: Variable 'a' at (1) cannot have both the OPTIONAL and the VALUE attribute because procedure 'bar' is BIND(C)
> 
> ```
> 
> ifx:
> 
> ```txt
> /app/example.f90(5): error #8238: A dummy argument with the VALUE attribute cannot have the OPTIONAL attribute in a BIND(C) procedure. [A]
> subroutine bar(a) bind(c)
> ------------------^
> 
> ```
> 
> flang
> 
> ```txt
> error: Semantic errors in /app/example.f90
> /app/example.f90:6:35: error: VALUE attribute may not apply to an OPTIONAL in a BIND(C) procedure
> integer, value, optional :: a
> ^
> 
> ```
> 
> nvfortran
> 
> ```txt
> NVFORTRAN-S-1269-Dummy argument a cannot have both the VALUE and OPTIONAL attributes because procedure bar has the BIND attribute (/app/example.f90: 6)
> NVFORTRAN/x86-64 Linux 26.1-0: compilation completed with severe errors
> 
> ```
> 
> NAG Fortran:
> 
> ```txt
> NAG Fortran Compiler Release 7.2(Shin-Urayasu) Build 7203
> Error: test_optional.f90, line 9: Argument A of BIND(C) procedure BAR has both the OPTIONAL and VALUE attributes
> 
> ```

All compilers caught the problem, however the LFortran compiler message is not clear (reported [here](https://github.com/lfortran/lfortran/issues/11080))

---

<div class="post-metadata">

**Author:** ![hkvzjal](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/hkvzjal/32/3055_2.png) [@hkvzjal](https://fortran-lang.discourse.group/u/hkvzjal)\
**Post date:** [April 14, 2026, 6:57pm UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/19 "2026-04-14T18:57:40Z")

</div>

> [@ivanpribec](#):
>
> Goes to show that Fortran programmers don’t make use of the `VALUE, OPTIONAL` attribute pair very often…

It would have never crossed my mind that this was meant to work. Looks interesting and promising. This is the first time I see these two put together.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [April 15, 2026, 4:38am UTC](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852/20 "2026-04-15T04:38:41Z")

</div>

> [@hkvzjal](#):
>
> This is the first time I see these two put together.

This looks like a good solution to this optional argument issue. Basically the `value` attribute replaces the `intent(in)` attribute, but it allows the argument to be safely modified. If only compilers supported it in a reliable way.

The other combinations of `intent()` and `optional` still need some workaround effort on the programmer’s part.

[Next page](https://fortran-lang.discourse.group/t/trick-for-optional-arguments-with-defaults/10852.md?page=2)
