j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
175 stars 14 forks source link

Unused attribute #316

Open ivan-pi opened 9 months ago

ivan-pi commented 9 months ago

When passing procedures as callbacks, sometimes a subset of the expected procedure parameters is not required and goes unused. Compiler tends to emit (false) warnings for unused parameters, despite this being deliberate in such cases.

  subroutine myode(n,t,y,yp,ptr)
    integer, value :: n 
    real(wp), intent(in) :: t, y(n)
    real(wp), intent(out) :: yp(n)
    type(c_ptr), value :: ptr  ! ptr is unused

    real(wp), parameter :: k1 = 0.1_wp, k2 = 0.05_wp
    yp(1) = -k1*y(1)
    yp(2) =  k1*y(1) - k2*y(2)
    yp(3) =  k2*y(2)
  end subroutine

In C++17, it is possible to suppress warnings on unused entities using the [[maybe_unused]] attribute:

[[maybe_unused]] void f(int n, double t, double *y, double *dydt, 
        [[maybe_unused]] void *params)

Another convention to prevent inadvertent use in C/C++ is to leave the dummy arguments unnamed:

void f(int n, double t, double *y, double *dydt, 
        void * /* params */)

In MATLAB, one can also ignore function inputs using the ~ symbol:

function dydt = f(t,y,~)

Is there interest to have something similar in Fortran? An attributes syntax could be used for other purposes too.

certik commented 9 months ago

Good idea. Probably type(c_ptr), value, unused :: ptr ! ptr is unused seems the most natural.

ivan-pi commented 8 months ago

The reason it is called maybe_unused in C++ is that due to preprocessor logic or template meta-programming, you can end up with situations where a variable appears to be used, but it gets cut out before the function reaches compilation. With a potential preprocessor in 202Y is this something for consideration here too?

certik commented 8 months ago

Can you show an example of this? Isn't the use case rather that a given variable can both be used and unused, depending on a preprocessor option? But it's never "maybe used" (some kind of superposition of used and unused?), it seems it is always either used or unused.

FortranFan commented 8 months ago

@ivan-pi wrote Oct. 6, 2023 05:37 PM EDT:

.. Is there interest to have something similar in Fortran? ..

For whatever it's worth, my firm opinion is something like "maybe_unused" does not fit in the language standard but specific processor (compiler) implementations may choose to do better to enhance the experience of their users.

I think there are two parts to the underlying issue:

  1. First is the immediate annoyance with the "warning"s. To start with, note the language standard does not require a processor to detect and report the unused argument case, so I do not see why the language standard should include anything to alleviate what an overeager compiler does when asked to put on its pedantic hat. To address the annoyance of practitioners with undesired warning is this specific scenario, collaboration by the practitioners who can't bear the annoyance with the compiler implementors is recommended. In the case of LFortran, @certik is setting a great example by championing a compiler/toolset ecosystem that works best for practitioners causing the least annoyance. @certik thus establishes the paradigm, "where there is will, there is a way". And the Community of LFortran can come up with best ideas together with @certik and team to take care of this. In the case of Intel Fortran users, the workflow will be for those "annoyed" with it to post threads at Intel Fortran forum and get Intel Support staff to work with Intel's Fortran development team to figure this out. In the interim, a significant userbase uses a build system outside of fpm such as Visual Studio IDE and there are ways to suppress specific warning locally and which can mitigate the annoyance. In the case of gfortran, the users are the implementors, whether they like it or know it or not! And the annoyed users need to then become compiler developers and sort this one out in their compiler itself.
  2. Next is the longer term aspect with Generics. Currently the Fortran standard does not include adequate semantics toward resolution of generic interfaces, meaning a procedure with interface A cannot always be disambiguated relative to interface B. This places, what I see as needless, limitations on library developers. And in the case of callback facilities needed by some libraries, it leads to scenarios as shown by @ivan-pi , where some received arguments can be unused in user procedures for the callback. In some cases, as an (erstwhile) library developer, I have found the OPTIONAL attribute to come in handy. But it is not always the case. I do think the J3 Generics subgroup, either directly or via supplemental direction to other subgroup such as /Data, should do the needful to ensure the language standard offers better. I will elaborate in a subsequent comment.
certik commented 8 months ago

Another idea is to do what Rust does, where the compiler asks the user to prefix a variable name with "_" to avoid the unused warnings.

Thanks @FortranFan for your comments. Yes indeed, compiler cooperation will be key here.

FortranFan commented 8 months ago

2. I will elaborate in a subsequent comment.

Consider this example:

module m
   abstract interface
      function Ifunc1(x) result(r)
         integer, intent(in) :: x
         integer :: r 
      end function
      function Ifunc2(x, y) result(r)
         integer, intent(in) :: x
         integer, intent(in) :: y
         integer :: r 
      end function
   end interface
   interface solve
      module procedure solve1
      module procedure solve2
      module procedure solve3
   end interface
contains
   subroutine solve1(x, proc)
      integer, intent(inout) :: x
      procedure(Ifunc1) :: proc
      x = proc( x )
   end subroutine 
   subroutine solve2(x, y, proc)
      integer, intent(inout) :: x
      integer, intent(in) :: y
      procedure(Ifunc2) :: proc
      x = proc( x, y )
   end subroutine 
   subroutine solve3(x, proc)  !<-- indistinguishable from solve1
      integer, intent(inout) :: x
      procedure(Ifunc2) :: proc
      integer :: y
      y = 0
      x = proc( x, y )
   end subroutine 
end module 
C:\temp>gfortran -c -ffree-form m.f
m.f:19:20:

   19 |    subroutine solve1(x, proc)
      |                    1
......
   30 |    subroutine solve3(x, proc)
      |                    2
Error: Ambiguous interfaces in generic interface 'solve' for 'solve1' at (1) and 'solve3' at (2)

Improved semantics in the language can take into account specific elements of the interface e,g., Ifunc1 vs Ifunc2 in the above example to resolve the generic interface solve. After all, the processor is already aware of this - see below.

module m
   abstract interface
      function Ifunc1(x) result(r)
         integer, intent(in) :: x
         integer :: r 
      end function
      function Ifunc2(x, y) result(r)
         integer, intent(in) :: x
         integer, intent(in) :: y
         integer :: r 
      end function
   end interface
   procedure(Ifunc1), pointer :: pfunc1 => myfunc
contains
   function myfunc(x, y) result(r)
      integer, intent(in) :: x
      integer, intent(in) :: y
      integer :: r
      r = x + y 
   end function
end module 
C:\temp>gfortran -c -ffree-form m.f
m.f:13:49:

   13 |    procedure(Ifunc1), pointer :: pfunc1 => myfunc
      |                                                 1
Error: Interface mismatch in procedure pointer assignment at (1): 'myfunc' has the wrong number of arguments
klausler commented 8 months ago

In the case of gfortran, the users are the implementors, whether they like it or know it or not! And the annoyed users need to then become compiler developers and sort this one out in their compiler itself.

Wait, what? Why are GNU Fortran users all "implementors", but users of other compilers not?

FortranFan commented 8 months ago

Why are GNU Fortran users all "implementors", but users of other compilers not?

gfortran can really benefit from more FOSS volunteers to advance the compiler such as with pending standard features from Fortran 2003 onward and to help resolve the growing list of open incidents in their GCC Bugzilla system.

Users of gfortran themselves are welcomed to be such FOSS volunteers, especially if they seek more timely attention to matters of interest to them i.e., they can become the implementors.

Same also applies with LFortran e.g., @certik can be both an implementor and an user.

Consider the following:

   call sub( n )
contains
   subroutine sub( x )
      integer, intent(in) :: x
      print *, "Hello World!"
   end subroutine
end 

But now in this case the user can employ a compiler option -Wno-unused-dummy-argument. Presumably though that may be seen as a bit of an effort or difficult with preconfigured build systems - dunno what all OP has in mind here/ But my suggestion is to either work with GCC/gfortran FOSS volunteers to refine -Wall because it is not strictly all warnings and thus unused dummy arguments can be excluded or think of another solution. But any of this may require the said "annoyed" user to become a gfortran contributor given where things stand with gfortran.

C:\temp>gfortran -c -ffree-form -Wall -Wno-unused-dummy-argument p.f

C:\temp>

The bottom-line to me is this does not appear a language standard matter.

septcolor commented 5 months ago

If this feature becomes available, I will definitely use it to suppress warnings about intentionally unused variables (because I always attach a check option to catch all unused variables).

type(Foo_t), unused :: foo
class(Myclass_t), unused :: this

To mimic this feature, I am using a CPP macro + associate to cheat compilers, like

#define _touch_(x) associate(dum__ => x); endassociate

and use it like _touch_(foo).