Implicit typing and backwards compatibility

They have been proposed, just that they are in separate threads for good reason:

My hunch is #78 above can be addressed separately and perhaps more readily. I expect the J3 committee to be able to iron out any wrinkles and develop a good solution based on the proposal without any issues with backward compatibility if they take it up. I hope a solution similar or same as the one in that thread makes it to Fortran 202Y.

Nonetheless, the elimination of implicit mapping is a fundamental item and one that touches upon a core aspect and a value and I hope this too can make into Fortran 202Y.

1 Like

Although that might well be an unintended error, I can think of some situations where that is exactly what the programmer might want to do.

My general feeling about this issue is that the default real kind should be the supported real kind with the least precision. That would also be the kind for any constant that does not have its kind specified. If the programmer wants something more accurate than that, or of a specific kind for some other reason, then the kind should be specified explicitly. This is a simple rule that is easy to remember. The current standard allows the default real kind to be other than that with the least precision, and the default kind can be modified with compiler options by several current compilers. Storage sequence requirements require that double precision occupy two of those storage units, so if a compiler supports, say 5 real kinds, then there might be several conforming choices for which one is the default.

There is some interest among numerical analysts in using real kinds that occupy one 8-bit byte. There are several kinds, with the bits partitioned in the various possible ways between the sign, the exponent, and the mantissa. In this case, the fortran default real kind would probably remain real32, or something similar, so my idea of the default real being the one with the least precision might not be very useful.

The idea of default kind for constants being the one with the maximum precision causes several problems. First, the default real kind would no longer correspond to the default constant kind, so that would result in a variety of backwards compatibility problems. Another problem is that if an untyped real constant were used in an expression, then the type and kind promotion rules would require that the expression must be evaluated partially or completely in that highest precision. That is usually not what the programmer would want, especially if that highest precision is done with software emulation and is very slow.

1 Like

I’d disagree with the Matlab-like syntax point. Modern Fortran has indeed a very similar array syntax wrt Matlab, much much more than Python/Numpy. Maybe Julia is a little more comfy, having built-in overloaded operators, but you could always define those in Fortran (which again calls for your previous point about libraries, but I think that’s almost solved with the new stdlib or older efforts like SciFortran, for basic stuff; and advanced and extended ecosystem is what we all strive for, as much as Julians I’d say).

The real missing killer feature is fast development through interactive workflows (REPLs in a nutshell), which is the main reason for LFortran development, as I understand (or at least the main reason for my personal excitement about the project!).

Let’s be total clear: a newcomer to the language would never, EVER, look for a copy of a F66-oriented book, written in the 70s, to get a grasp of Fortran. Rather he/she would just google fortran and end here or on similar pages about modern fortran.

Also no other popular computing language has an enforced implicit type system. You either get explicit strong typing or total python-like freedom (which in any way compares to what fortran implicit mapping does).

2 Likes

How about something like
implicit real(kind=xxx) (constant)
That could serve those who really know what they want and would not break any existing code.

I also see a (custom) implicit mapping as a great opportunity for interactive usage (through LFortran or similar efforts). Really it seems kind of a great alternative to totally free dynamic typing (where it can lead to severe performance problems, see e.g. all the threads about type instability in Julia discourse).

Nevertheless nothing about that speaks about what should be the default :slight_smile:

In quasi-Fortran, I think implicit mapping should be based on the type of the RHS and not the variable name, so that

i = 42
x = 3.14d0
name = "Fred"

mean that earlier lines of code

integer :: i
real(kind=kind(1.0d0)) :: x
character (len=:), allocatable :: name

are assumed to be present. If you later wrote i = 3.14 you would get either a warning or an error about a type cast, since i is still an integer, and name = 3.14 would be illegal since name is a character variable. Type instability would not be allowed. Maybe the default numeric literal should be double precision, with the the suffix e0 required for a single precision constant. Of course quasi-Fortran should be machine-translatable to standard Fortran.

2 Likes

You could still write x = 0 with the current meaning, provided that x were previously declared real. Inferring the type from the RHS would only be done the first time an undeclared variable appeared. My previous suggestions were for an interactive environment such as LFortran, not for standard Fortran, which is why I referred to quasi-Fortran. (Of course LFortran, besides providing a REPL, also aims to be a compiler of standard Fortran, in a different mode.)

1 Like

I agree, inferred typing based on the RHS would be a great feature. Definitely that would lower the barrier of entry for people coming from more dynamic languages like Python. Probably only for a REPL version of Fortran though.

But maybe it would be possible within regular Fortran with some extra flag?

let x = 1   ! x is now an integer

Has this been proposed before? Seems like another language has that (Swift maybe)?

2 Likes

You might be looking for

Yes, that’s one of the goals.

We can have an optional --infer option, that you could enable in interactive mode (Infer the types of variables? (#295) · Issues · lfortran / lfortran · GitLab) that could do that.

For regular code, I actually do not like inferring the type, I like the types to be explicit. In C++ also, I do not like using the auto keyword.

3 Likes

In a sense, one can presume a Fortran 2003 and later processor needs the bulk of the machinery toward type inference with its support of the ASSOCIATE construct.

The question is whether and how to take advantage of and perhaps extend the type inference toward particular situations in Fortran without starting to “abuse” it.

I don’t know what is right here.

Only that in some parlance, C++ auto is seen very positively and adopted eagerly in practice e.g., in code segments where the type declarations are so obvious as to be unnecessary.

   associate ( n => 1 )
      call print_type( n, "n" ) 
   end associate
   associate ( r => 1.0 )
      call print_type( r, "r" ) 
   end associate
   associate ( s => "abc" )
      call print_type( s, "s" ) 
   end associate
contains
   subroutine print_type( a, nam )
      class(*), intent(in) :: a
      character(len=*), intent(in) :: nam
      select type ( a )
         type is ( integer )
            print *, nam, " is integer"
         type is ( real )
            print *, nam, " is real"
         type is ( character(len=*) )
            print *, nam, " is character with length-type parameter of ", len(a)
         class default
            ! ??
      end select
   end subroutine 
end
C:\Temp>gfortran p.f90 -o p.exe

C:\Temp>p.exe
 n is integer
 r is real
 s is character with length-type parameter of            3

I think this also happens in an assignment to a polymorphic variable, as in

class(*), allocatable :: var
!...
var = (1.0,1.0)  ! var gets complex dynamic type
!...
var = 1.23 ! var gets real dynamic type

The usability of this feature is, however, not great, as it still requires select type to use the assigned value (unless I miss something),

If ASSOCIATE would do the same thing for a CLASS(*) variable,
but acting as an explicit declaration instead of just associating
a new name to the variable I would use it. Implementing
that might not be feasible (?), at least without some syntax
giving a list of allowed types but from a user standpoint that
would be nice. Something like …

program testit
integer :: a=1
real :: b=100.0
   call something(a,b)
contains
subroutine something(arg1,arg2)
class(*) :: arg1, arg2
   ! if doing the associate were equivalent to
   ! TYPE(integer(kind=int32)) :: a=arg1
   ! TYPE(real(kind=real32)) :: b=arg2
   ! instead of just associating the names for this call
   associate( a=> arg1, b=> arg2)
   ! then you could use the variables as if non-polymorphic
   write(*,*)a*b
   end associate
end subroutine something
end program testit

or if TYPE() could take a list

TYPE(integer,real) :: arg1, arg2

would be nice too if it automatically generated the generic
code. It just seems like it might explode in complexity when
many arguments are passed that are CLASS(*).

I’m afraid it would ruin the idea of associate which includes inferring the type of LHS of => from RHS.
The only useful solution I see would be to allow some form of assignment of a polymorphic variable to a strongly typed one outside of the select type construct. If just using var=polyvar is not acceptable, maybe it could be using explicit conversion function, like a=real(polyvar) with non-numeric types allowed if there is an assignment defined between the dynamic type of polyvar and the LHS

1 Like