Passing Internal Subprogram as Argument?

Are there plans to support the Fortran 2008 feature that currently produces the following error?

PGF90-S-0439-An internal subprogram cannot be passed as argument

Passing an internal procedure is a very powerful construct that allows us to connect modern OOP constructs with solver libraries that only accept procedures with a specific interface. While the solver library is churning away, calling our internal procedure, the internal procedure has access to the containing scope’s passed object dummy argument and all it represents.

Thanks.

We’ll be adding F2008 features throughout the year. Though, I don’t know exactly when this particular feature will be available.

  • Mat

Mat,

Can you add my voice to making this a priority? GEOS-5 GCM is now using ESMF_MethodAdd which has a couple interfaces:

http://www.earthsystemmodeling.org/esmf_releases/public/ESMF_5_2_0rp3/ESMF_refdoc/node4.html#SECTION04064000000000000000

Our code as is uses the one wherein you pass in a subroutine and we see:

PGF90-S-0439-An internal subprogram cannot be passed as argument - optics_compute (mam_optics_calculator.F90: 182)
PGF90-S-0439-An internal subprogram cannot be passed as argument - optics_compute (mam_optics_calculator.F90: 182)
PGF90-S-0155-Ambiguous interfaces for generic procedure esmf_methodadd (mam_optics_calculator.F90: 182)
PGF90-S-0439-An internal subprogram cannot be passed as argument - optics_compute (mam_optics_calculator.F90: 182)

I’m currently trying to get our code to use the second one (pass in a string) though it may or may not work as I’ll have to figure out the exact way you guys decorate procedure names.

But, gfortran 4.9.1 and Intel 15.0.2 both allow the first, so I’m guessing it is this feature from this forum post.

Matt

Well, as an aside, the code I can exercise normally looks like this:

call ESMF_MethodAdd(aero, label='aerosol_optics', userRoutine=aerosol_optics, __RC__)

and this works with Intel and GNU.

I’ve tried these three ways with PGI (14.7 in this case):

call ESMF_MethodAdd(aero, label='aerosol_optics', userRoutine="aerosol_optics", __RC__)

call ESMF_MethodAdd(aero, label='aerosol_optics', userRoutine="gocart_gridcompmod_aerosol_optics", __RC__)

call ESMF_MethodAdd(aero, label='aerosol_optics', userRoutine="gocart_gridcompmod_aerosol_optics_", __RC__)

All will compile, but none will run. The latter call has the userRoutine as I see when I ‘nm GEOSgcm.x | grep aerosol_optics’.

My next thought is that I need to do more. ESMF says:

userRoutine
Name of user-supplied subroutine to be associated with the label, specified as a character string.
The subroutine must have the exact interface shown in ESMF_MethodStateAdd for the userRoutine argument. Arguments in userRoutine must not be declared as optional, and the types, intent and order must match. The subroutine must be either a module scope procedure, or an external procedure that has a matching interface block specified for it. It must not be an internal procedure which is contained within another procedure.

[sharedObj]
Name of shared object that contains userRoutine. If the sharedObj argument is not provided the executable itself will be searched for userRoutine.

So, aerosol_optics is a subroutine that is only “contained” by the module GOCART_GridCompMod itself, not by a run method or anything.

My fear now is because we compile static not shared that this is just might be undoable within the bounds of ESMF until the F2008 interface is supported.

Thanks Matt. I passed this one on to the folks adding F2008 support.

  • Mat

Mat,

As an aside, let’s say the other interface could do what I want, what would be the correct way to decorate the routine name if it could work? That is, would I use the output of ‘nm executable.exe’ grepped to find the routine (aka: modulename_routinename_)?

Yes, you can use nm to grab the symbol name from the binary or objects and yes the symbol should be “modulename_routine_”.

Unfortunately I don’t know why ESMF wouldn’t call this routine.

  • Mat

I think I do. It turns out that PGI is being much stricter than Intel (not hard) and gfortran (surprising). The routine that is failing it turns out is not in a MODULE. Thus, it does not have an explicit interface. It’s a subroutine in a file that is just program and subroutines/functions. If I add an explicit interface block, it compiles.

Some of the other files that use this don’t throw an error because they are in modules!

Amazingly, PGI is the only compiler that, I guess, doesn’t build an interface “automagically”? I can’t see how gfortran isn’t complaining (Intel seems to let everything slide without strictness flags).

Sorry about this!

Matt

Hi Matt,

Routines with optional arguments are required to have an interface. My guess is that the other compilers are just getting lucky since I highly doubt they are implicitly creating an interface. Maybe if the definition is visible it’s possible, but I doubt that this is case.

  • Mat

This feature is now available in PGI Version 18.4.