A feature I would love to see in Fortran is function objects, objects which can be called as if they are functions. I recently discovered that Fortran does not intrinsically have argument capture, and I think the workaround for this - writing a type which contains a procedure pointer and stores the captured variables explicitly - is clunky, because the type cannot be called like a function.
Proposed syntax
I would like to propose the syntax operator(())
, which would be used in exactly the same way as e.g. operator(*)
and operator(//)
. This would allow for the definition of more natural lambda types, e.g.
module lambda_module
abstract interface
function foo(input1,input2) result(output)
integer, intent(in) :: input1,input2
integer :: output
end function
end interface
type :: Lambda
procedure(foo), pointer :: func
integer :: captured_variable
contains
generic, public :: operator(()) => call_Lambda
procedure, private :: call_Lambda
end type
function call_Lambda(this,input) result(output)
class(Lambda), intent(in) :: this
integer, intent(in) :: input
integer :: output
output = this%func(input, this%captured_variable)
end function
end module
and these lambda types might be used like
program test
use lambda_module
add_one = generate_lambda_add_one()
write(*,*) add_one(3) ! Writes "4".
contains
function generate_lambda_add_one() result(output)
type(Lambda) :: output
output = Lambda(add_integers, 1)
contains
function add_integers(input1,input2) result(output)
integer, intent(in) :: input1,input2
integer :: output
output = input1+input2
end function
end function
end program
Containers
I think this would also be helpful for writing containers which feel more “Fortranic”, so that container element access feels more like element access for intrinsic arrays, e.g.
type :: Array
integer, allocatable :: contents(:)
contains
generic, public :: operator(()) => access_Array
procedure, private :: access_Array
end type
elemental function access_Array(this,index) result(output)
class(Array), intent(in) :: this
integer, intent(in) :: index
integer :: output
output = this%contents(index)
end function
type(Array) :: foo
foo = Array([2,4,8,16,32])
write(*,*) foo([1,5,3]) ! Writes "2 32 8"
Syntax clash
I think this would be a relatively small syntactical addition, which hopefully shouldn’t cause too many headaches for the compilers.
The main syntax issue I see is how to use arrays of function objects, e.g. if you have
type(Array), allocatable :: foo(:)
foo = [Array([1,2]), Array([3,4])]
write(*,*) = foo(1)
then it’s unclear whether what is written should be the first element of foo
, i.e. Array([1,2])
, or the result of calling access_Array
on foo
elementally, i.e. [1,3]
.
For this I think I would favour leaning in to the clash between function call and array access syntax, and have
-
foo(1)
return the first element of foo -
foo(:,1)
callaccess_Array
onfoo
elementally.
Summary
So, what does everyone think? Is this an idea that’s been proposed before, and was it rejected for some reason? Is this even the right forum for these kinds of feature proposals? I’d love to hear your thoughts.