In Java there is a nifty function that any class descending from Object
has:
public String toString()
the function in it self is not very magical, but the way that the Java interpreter uses it makes it very, well, useful. And, of course, this in not something that is of live-or-die importance, but a very nice-to-have, making life easier for somewhat lazy coders. As far as I can tell anything similar doesn't exist in Fortran (or in many other languages).
Am I wrong? Does something like this exist? Or, is there something similar hidden in Fortran lore?
For those who are not familiar with Java: Simply (but slightly inaccurate) said, if an object variable is used (without referring to any of its members) in any place that a String is expected, the Java interpreter looks up the toString()
method for the variable's class, defaulting up through the hierarchy (all the way to Object
). Thus, every object has some toString()
available.
Implementing a toString()
function into a class (or type) in Fortran is not much hazzle. Well, that kinda depends on the complexity of the type, and on what the user wants the function to return.
It would be far more convenient to write:
write(*,*) somevariable
instead of
write(*,*) somevariable%toString()
similar for assignments of course
character (len = *) :: str
str = somevariable
instead of
str = somevariable%toString()
This is, of course, related to type casting. Implicit type casting, if I am not mistaken.
I am not looking to start a long discussion on this, as I have little more to contribute than what I have already written.
Fortran doesn't have a strong concept of "if object of type Y is given where one of type X is expected, convert it to one of type X". This covers different types of numeric objects (Y double precision, X real, say) as much as derived types and strings.
You'll see this in things like argument mismatches in procedure references and so on.
We do have type conversion in some cases, like in x+y
where those two objects are of different types.
So, a reference like somevariable
is always1 a reference to that object, rather than any one (or more) of its components or type-bound procedures/binding names.
In something like
call dosomething(somevariable)
where dosomething
expects a character but somevariable
is not a character, there can never be an implicit conversion carried out for you.
However, in the two cases you are interested in, there are means to say instead that somevariable
as a derived type is expected, but that something else happens instead of immediately processing that type.
For example (see other questions and answers for precise explanations), we can define a type t
with a generic write(formatted)
and an interface for assignment(=)
which has a character left-hand side and type(t)
right-hand side:
module mod
type t
integer :: i=0
contains
procedure :: write
generic :: write(formatted) => write
end type t
interface assignment(=)
module procedure assign
end interface assignment(=)
contains
subroutine write(dtv, unit, iotype, v_list, iostat, iomsg)
class(t), intent(in) :: dtv
integer, intent(in) :: unit
character(*), intent(in) :: iotype
integer, intent(in) :: v_list(:)
integer, intent(out) :: iostat
character(*), intent(inout) :: iomsg
write (unit, "(A)", iostat=iostat, iomsg=iomsg) "Object says hello"
end subroutine write
subroutine assign(lhs, rhs)
character(:), allocatable, intent(out) :: lhs
class(t), intent(in) :: rhs
lhs = "From assignment"
end subroutine assign
end module mod
The defined output procedure can be called with the dt
edit descriptor (or using list-directed output), and the defined assignment as usual:
use mod, only : t, assignment(=)
character(:), allocatable :: str
print '(dt)', t()
str = t()
print '(A)', str
end
1 The reference to a derived type object can be expanded to its component order in intrinsic data transfer of the object when those components are all accessible.