One possible way of getting a non-assignable object while using a form of RAII, is to use associate.
First you need to overload the structure constructor:
function new_ext_t(val) result(this)
integer, intent(in), optional :: val
type(ext_t) :: this
if (present(val)) then
this%val = val
end if
end function
Next you build a facade module that only exposes the overloaded structure constructor, but keeps the type hidden:
module test_facade
use test, only: ext_t => new_ext_t
end module
Finally, you instruct consumers to use the container within an associate block:
program testprog
use test_facade, only: ext_t
implicit none
type(ext_t) :: a ! compile-time error
associate(ext => ext_t(3))
! ... access public members of ext ...
ext = ext_t(4) ! compile-time error
end associate
Inside the associate statement I believe you can still call any type-bound methods (not sure what happens if a method is intent(out)
). The objects is also supposed to be finalized upon exiting the associate block (see Should associate trigger automatic finalization?). Unfortunately, you may bump into issues with compiler support.
Their is a nice example of this pattern in the nlopt-f library for defining callbacks that get passed to a calling C routine.
Edit: If you need a copy, you can overload the structure constructor with a second method,
module test_facade
use test, only: new_ext_t, copy_ext_t
private
public :: ext_t
interface ext_t
procedure :: new_ext_t, copy_ext_t
end interface
end module
that can be used with a second associate statement:
associate(this => ext_t(3))
! ...
associate(copy => ext_t(this))
! ...
end associate
end associate