While reading the OO techniques tutorial by Reinhold Bader, I came across this example:
type polynomial
real, allocatable :: value(:)
end type polynomial
type(polynomial) :: a
a = polynomial( null() )
I was a bit surprised that this works, but of course a pointer can act as a scalar or an array. In this case I expected, naïvely, a zero-sized array. But gfortran and ifx both show upon examining the allocation status that the component value is not allocated. I guess this is correct behaviour - it is a means to postpone the actual setting of a component. Still, the result is curious and I think the tutorial should avoid it.
F2023 7.5.10p6 Construction of derived type values
If a component of a derived type is allocatable, the corresponding constructor expression shall be a reference to the intrinsic function NULL with no arguments, an allocatable entity of the same rank, or shall evaluate to an entity of the same rank. If the expression is a reference to the intrinsic function NULL, the corresponding component of the constructor has a status of unallocated.
Ah, that makes it clearer but for this tutorial I would say that an explanation along these lines is desirable. (I never encountered this feature before.)
I am not sure I like the idea of bypassing deallocate. It is harmless here (but also pointless), but if a%value is allocated then there is probably a memory leak.
Behaviour of gfortran changed (became correct) at 13.2 in the case of a zero-sized array supplied for allocatable component in structure constructor. Compiler Explorer
Quite right. I hadn’t thought it through. I was thinking about something like the following, which isn’t standard conforming.
program null01
type polynomial
real, allocatable :: value(:)
end type polynomial
call f
contains
subroutine f
type(polynomial) :: a
a = polynomial( null() )
a%value = [1.0,2.0]
a%value = null()
end subroutine
end program
gfortran -Wall -c null01.f90
null01.f90:18:14:
18 | a%value = null()
| 1
Error: NULL appears on right-hand side in assignment at (1)
make: *** [Makefile:6: null01.o] Error 1
I was curious what would happen if the call to null() in a constructor is applied to an ordinary scalar:
program fillnull
implicit none
type :: simple
integer :: value = 10
end type simple
type(simple) :: a
write(*,*) 'Default: ', a
a = simple(null())
write(*,*) 'After null(): ', a
end program fillnull
This code is not accepted by gfortran (14.1.0):
Error: The NULL in the structure constructor at (1) is being applied to component 'value', which is neither a POINTER nor ALLOCATABLE
but ifx (2025.0.0) accepts it. I guess gfortran is right in throwing an error.
My (current) understanding is that allocatable variables are always initially unallocated, no matter whether they are type components or not. Is my understanding above correct…? (If so, I wonder what is the purpose of passing null() as an actual argument in the above example (possibly for clarity…?))
EDIT: I guess another possibility might be that null() is used as a placeholder (?) when a derived type has multiple components and the programmer does not want to use keyword arguments but rather initialize all of them with positional arguments (like a = simple(100, null(), "hello")).
The example in question does not pass null() as an actual argument, though I admit it superficially looks that way. In the examples here a structure constructor is used, with null() being one of the values corresponding to a derived type component.
Fortran 2023 (but not earlier) does have syntax for specifying that an argument is omitted: .NIL..
As for @Arjen 's example, I agree that ifx is in error in not reporting the usage as invalid.