# How to have a generic interface for both allocatable and non allocatable dummy?

**URL:** <https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114>\
**Category:** Help\
**Created:** [July 8, 2023, 8:45pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114 "2023-07-08T20:45:47Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [July 8, 2023, 8:45pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/1 "2023-07-08T20:45:47Z")

</div>

A toy example is better than long explanations:

```auto
module foo
    implicit none
    interface bar
        module procedure bar_na, bar_a
    end interface
contains
    subroutine bar_na(a,b)
    integer, intent(in ) :: a(:)
    integer, intent( out) :: b(:)
        b = -a
    end subroutine

    subroutine bar_a(a,b)
    integer, intent(in ) :: a(:)
    integer, intent( out), allocatable :: b(:)
        b = -a
    end subroutine
end module

```

This produces the following compilation error:

```auto
/app/example.f90:7:21:

    7 | subroutine bar_na(a,b)
      | 1
......
   13 | subroutine bar_a(a,b)
      | 2 
Error: Ambiguous interfaces in generic interface 'bar' for 'bar_na' at (1) and 'bar_a' at (2)

```

Is there a possible workaround?

---

<div class="post-metadata">

**Author:** ![shahmoradi](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/shahmoradi/32/3151_2.png) [@shahmoradi](https://fortran-lang.discourse.group/u/shahmoradi)\
**Post date:** [July 8, 2023, 9:08pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/2 "2023-07-08T21:08:07Z")

</div>

I think they are theoretically distinguishable, but the standard has avoided it so far (perhaps for good reasons). Two approaches I often take to resolve the ambiguity are to either 1) merge the allocatable dummy argument `b` and `a` into a single `allocatable, intent(inout)` dummy argument, or 2) pass the length of `b` as an explicit `intent(in)` or more frequently `intent(out)` dummy argument in either of the two interfaces. The best approach depends on the problem being solved.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [July 8, 2023, 10:40pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/3 "2023-07-08T22:40:24Z")

</div>

> [@shahmoradi](#):
>
> I think they are theoretically distinguishable, but the standard has avoided it …

With inspired and willing compiler implementors, I too think the `callee` can be made to distinguish. However the issue is the `caller` side vis-a-vis the standard. The standard semantics, as arrived during the `Fortran 8X` saga during the 1980s, are such that the nonallocatable procedure instance is accessible to valid arrays of other attributes. Hence the `caller` faces ambiguity and it is at the root of the evil here.

With the work on Generics toward Fortran 202Y, I requested the J3 subgroups to get this specific aspect (and others) addressed by thinking out-of-the-box for some new standard extension that can help overcome the hurdle.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [July 8, 2023, 10:42pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/4 "2023-07-08T22:42:16Z")

</div>

> [@PierU](#):
>
> This produces the following compilation error:

This is because it is allowed for the programmer to pass an allocatable actual argument to bar\_na(). Thus the compiler cannot know which routine you want. In contrast, an array without the alloctable attribute cannot be passed to bar\_a(), and the compiler knows that and will warn you at compile time of the incompatibility.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [July 8, 2023, 10:50pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/5 "2023-07-08T22:50:37Z")

</div>

> [@FortranFan](#):
>
> With the work on Generics toward Fortran 202Y .

So consider what it would take for a lay practitioner of Fortran to author a `SWAP` generic with the new template construct - this [**link**](https://github.com/j3-fortran/generics/blob/main/examples/swap/alt_swap_m.F90) has the likely 202Y syntax: So with this `SWAP` case, the challenge is rather similar to that in the original post here.

```fortran
..
   template swap_t(T, N)
      private

      public :: swap
      public :: swap_dyn
   
      type :: T
      end type T
      integer, parameter :: N
   
      interface swap
         module procedure swap_
      end interface swap

      interface swap_dyn
         module procedure swap_ptr
         module procedure swap_alloc
      end interface swap_dyn

```

Frankly I think it is ridiculously verbose to ask a template author to do all this when a processor can be instructed to take care of this with good semantic improvement(s) in the language and a compact syntax to go with it.

---

<div class="post-metadata">

**Author:** ![everythingfunctional](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/everythingfunctional/32/176_2.png) [@everythingfunctional](https://fortran-lang.discourse.group/u/everythingfunctional)\
**Post date:** [July 9, 2023, 1:28am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/6 "2023-07-09T01:28:43Z")

</div>

Given the calling code:

```auto
a = [1, 2, 3]
b = [4, 5, 6]
call bar(a, b)

```

What should the compiler do? Deallocate `b` and call `bar_a`, or simply call `bar_na`?

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [July 9, 2023, 3:13am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/7 "2023-07-09T03:13:39Z")

</div>

> [@shahmoradi](#):
>
> I think they are theoretically distinguishable, but the standard has avoided it so far (perhaps for good reasons)…

So here, my take is Fortran 90 got off on the wrong foot when `ALLOCATABLE`s and `POINTER`s got introduced in a standard revision which also had generic interfaces. Thus when it came to disambiguation, Fortran 90 had statements such as:

 ![image](https://global.discourse-cdn.com/free1/uploads/fortran_lang/original/2X/f/fc673b5a58096311e886e164595368f53d264000.png)

where type, kind, and rank got considered which later, starting Fortran 2003, came to be referred to as `TKR compatible` semantics.

I truly believe, with some intent and inventiveness of the part of standard bearers, Fortran 90 could have started off with consideration of type, kind, rank, and attribute in disambiguation, or what I refer to as **KART** compatible semantics given what I think is the order of importance in actual practice with generic procedures. So with this, Fortran 90 would have been like so:

```fortran
.
interface sub
   module procedure sub_a
   module procedure sub_b
   module procedure sub_c
end interface
,
subroutine sub_a( a, b )
   integer, intent(in) :: a(:)
   integer, intent(out) :: b(:)
.
subroutine sub_b( a, b )
   integer, intent(in) :: a(:)
   integer, intent(out), allocatable :: b(:)
.
subroutine sub_b( a, b )
   integer, intent(in) :: a(:)
   integer, intent(out), pointer :: b(:)
.
integer x(..), y(..)
call sub( x, y ) ! disambiguates to sub_a
.
integer u(..)
integer, allocatable, v(..)
call sub( u, v ) ! disambiguates to sub_b
.. and so forth   

```

Now, this would not have given the practitioners the short-cut to readily invoke procedures with nonallocatable, nonpointer array received arguments with actual that have either of these. But instead of a ready short-cut, in this case it might have worked out better if some other syntactical sugar, say the use of `( .. )`, around the actual arguments was selected e.g.,

```fortran
call sub( u, (v) ) ! disambiguates to sub_a due to `( .. )` around v denoting an expression a la ASSOCIATE construct

```

Oh well …

But I had very much wished for the Generics for Fortran 202Y to be designed around **KART** -compatible semantics, alas I failed.

---

<div class="post-metadata">

**Author:** ![shahmoradi](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/shahmoradi/32/3151_2.png) [@shahmoradi](https://fortran-lang.discourse.group/u/shahmoradi)\
**Post date:** [July 9, 2023, 3:33am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/8 "2023-07-09T03:33:51Z")

</div>

Agreed. There have been a few dozen instances among our library’s ~1500 generic interfaces where I wished the TKR rule could be more refined, particularly for allocatable arguments. We use the workarounds I mentioned above instead. It is manageable.

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [July 9, 2023, 6:49am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/9 "2023-07-09T06:49:48Z")

</div>

> [@RonShepard](#):
>
> This is because it is allowed for the programmer to pass an allocatable actual argument to bar\_na(). Thus the compiler cannot know which routine you want.

I was initially expecting the compiler to give priority to the “allocatable routine” in such a case.

> [@everythingfunctional](#):
>
> Given the calling code:
> 
> ```auto
> a = [1, 2, 3]
> b = [4, 5, 6]
> call bar(a, b)
> 
> ```
> 
> What should the compiler do? Deallocate `b` and call `bar_a`, or simply call `bar_na`?

call `bar_a` because `b` is allocatable. This could have been a rule. But I can now see ambiguous cases if a 3rd routine was provided to the interface with only the `a` dummy argument being allocatable. If the two actual arguments are allocatable, the compiler could still not decide which routine to call. This is maybe the reason why such a rule was not set in the first place.

> [@shahmoradi](#):
>
> Two approaches I often take to resolve the ambiguity are to either 1) merge the allocatable dummy argument `b` and `a` into a single `allocatable, intent(inout)` dummy argument, or 2) pass the length of `b` as an explicit `intent(in)` or more frequently `intent(out)` dummy argument in either of the two interfaces. The best approach depends on the problem being solved.

In my real use case, `a` and `b` don’t have the same type (so 1) won’t do) and/or the interface is the assignment(=) overload (so 2) won’t work).

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [July 9, 2023, 3:51pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/10 "2023-07-09T15:51:12Z")

</div>

bar\_na is unsafe (non-conformance when shapes of a and b differ), bar\_a is unsafe (if reallocation fails when shapes differ).  
Why would you even want to marry these two?

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [July 9, 2023, 5:29pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/11 "2023-07-09T17:29:11Z")

</div>

> [@PierU](#):
>
> > [@RonShepard](#):
> >
> > This is because it is allowed for the programmer to pass an allocatable actual argument to bar\_na(). Thus the compiler cannot know which routine you want.
> 
> I was initially expecting the compiler to give priority to the “allocatable routine” in such a case.

I would imagine this might be implemented by the compiler first finding all specific interfaces that match the call statement. If there are more than one that match, then there would be some kind of point system, where each of the candidates earns bonus points when the attributes of the dummy arguments match those of the actual arguments. For example, an allocatable dummy argument that matches an allocatable actual argument would result in some bonus points given to that interface. Then the compiler would select the matching specific interface with the most bonus points. What happens when there are several interfaces with the same bonus points? Who sets the bonus point values, the programmer, or the standard committee, or can each compiler be different? As I said before, this general approach sounds like it could be complicated and make programming more difficult, not easier.

As it now exists with TKR matching, the rules are rigged so that there can’t be multiple matches, and either an interface matches the call statement or it doesn’t. Every compiler is required to resolve the matching in the same way, so codes can be portable. That makes things simple for the compiler and, perhaps more importantly, simple for the programmer, but of course it imposes constraints on the interfaces that are allowed. In the example being discussed, if the programmer has an allocatable argument that he wants to be treated as allocatable within the subroutine, then he must call the specific `bar_a()`, he cannot call a generic interface and expect the compiler to pick the one he wants.

---

<div class="post-metadata">

**Author:** ![ashe](https://avatars.discourse-cdn.com/v4/letter/a/ce73a5/32.png) [@ashe](https://fortran-lang.discourse.group/u/ashe)\
**Post date:** [July 9, 2023, 6:40pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/12 "2023-07-09T18:40:34Z")

</div>

> [@RonShepard](#):
>
> > [@PierU](#):
> >
> > I was initially expecting the compiler to give priority to the “allocatable routine” in such a case.
> 
> I would imagine this might be implemented by the compiler first finding all specific interfaces that match the call statement. If there are more than one that match, then there would be some kind of point system, where each of the candidates earns bonus points when the attributes of the dummy arguments match those of the actual arguments.

A problem with this approach is that the meaning of a call can change when a procedure is added to the generic interface.

For example, you start with:

```fortran
  interface bar
    module procedure bar_1, bar_2
  end interface
  ...
  call bar(...)

```

Assuming it compiles, `bar` is resolved to precisely one of `bar_1` or `bar_2`.

But now you add:

```fortran
  interface bar
    module procedure bar_3
  end interface

```

Under this proposal, if `bar_3` is “better” by some measure, the meaning of the `call bar`  
might change to call `bar_3`. I think this would be very surprising.

The way it works currently, if `bar_3` can be added to the generic, it doesn’t change the meaning of calls that compile without it.

> [@RonShepard](#):
>
> As it now exists with TKR matching, the rules are rigged so that there can’t be multiple matches, and either an interface matches the call statement or it doesn’t. Every compiler is required to resolve the matching in the same way, so codes can be portable. That makes things simple for the compiler and, perhaps more importantly, simple for the programmer, but of course it imposes constraints on the interfaces that are allowed.

Compilers are good at implementing complex rules. What’s hard is specifying the rules unambiguously in the standard (look at how complicated the existing rules are already). And, as you mention, programmers have to understand them.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [July 9, 2023, 7:22pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/13 "2023-07-09T19:22:00Z")

</div>

> [@ashe](#):
>
> … Compilers are good at implementing complex rules. …

Nope, that’s not the case at all. What the compilers, starting from `IBM FORTRAN` circa 1956, are good at is in implementing code optimizations for which the few documented rules come after the fact, and the optimizations are approached more as fuzzy math, more black box, and perhaps even black art!

Instead when it comes to any rules with language semantics and syntax, there is great struggle to be good at their implementation.

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [July 9, 2023, 7:33pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/14 "2023-07-09T19:33:01Z")

</div>

@RonShepard @ashe I agree, and it was also implied in my answer to @everythingfunctional: disambiguying between allocatable and non-allocatable dummies doesn’t look possible in the general case (only in simple cases).

---

<div class="post-metadata">

**Author:** ![PierU](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/pieru/32/1848_2.png) [@PierU](https://fortran-lang.discourse.group/u/PierU)\
**Post date:** [July 9, 2023, 8:55pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/15 "2023-07-09T20:55:23Z")

</div>

> [@themos](#):
>
> bar\_na is unsafe (non-conformance when shapes of a and b differ),

So is any array assignement when the shapes differ. So what?

> [@themos](#):
>
> bar\_a is unsafe (if reallocation fails when shapes differ).

So is any allocation on assignment. So what?

> [@themos](#):
>
> Why would you even want to marry these two?

For instance to overload the assignment(=) with optional allocation on assignement in the case the LHS is an allocatable.

---

<div class="post-metadata">

**Author:** ![RonShepard](https://avatars.discourse-cdn.com/v4/letter/r/a3d4f5/32.png) [@RonShepard](https://fortran-lang.discourse.group/u/RonShepard)\
**Post date:** [July 9, 2023, 9:47pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/16 "2023-07-09T21:47:00Z")

</div>

> [@ashe](#):
>
> Under this proposal, if `bar_3` is “better” by some measure, the meaning of the `call bar`  
> might change to call `bar_3`. I think this would be very surprising.

If the new bar\_3() were added for this purpose, (say to optimize some specific case), then it would not be surprising that the new routine were called, it would be the expected behavior. However, I do agree in general that this would be a complicated programming environment compared to the current situation. But if a programmer wants to handle some case separately, say due to an allocatable, pointer, or target attribute (i.e. something that is beyond TKR), with a generic interface, then what are the options?

One such option would be to allow the value of an argument to determine which specific procedure is called. This is now done within fortran within a few generic intrinsic functions. For example, when you specify `REAL(x,KIND=wp)`, the return type depends on the value of `wp`. So this is equivalent to a situation where there are several `REAL()` functions, and the one that the compiler invokes depends (at compile time) on the TKR of the argument `x` and on the value of the dummy argument `KIND` (which I’ve invoked by keyword here, but that is not a requirement). For this particular case, `wp` must be known at compile time, so perhaps that kind of constraint could apply also to the situation with a user-written procedure. Although this capability is used by many intrinsic functions, it is not available currently for user-written procedures, so this would be a major advancement to the language.

BTW, this kind of language change occurred already for keyword arguments. Fortran 77 allowed keyword argument association only in some intrinsic procedures (e.g. OPEN, CLOSE, INQUIRE, READ, WRITE). Then f90 allowed this capability to be extended to user-written programs. Allowing a generic interface to select a specific procedure based on the value of one or more particular arguments would be a change of similar magnitude and scope.

---

<div class="post-metadata">

**Author:** ![ashe](https://avatars.discourse-cdn.com/v4/letter/a/ce73a5/32.png) [@ashe](https://fortran-lang.discourse.group/u/ashe)\
**Post date:** [July 10, 2023, 6:05pm UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/17 "2023-07-10T18:05:54Z")

</div>

> [@RonShepard](#):
>
> If the new bar\_3() were added for this purpose, (say to optimize some specific case), then it would not be surprising that the new routine were called, it would be the expected behavior.

Right, sometimes you want the meaning of `call bar` to change. But I think sometimes it is surprising. And good language design has to balance adding useful features to the language versus added complication for the programmers.

> [@](#):
>
> But if a programmer wants to handle some case separately, say due to an allocatable, pointer, or target attribute (i.e. something that is beyond TKR), with a generic interface, then what are the options?

One (somewhat kludgy) solution is to add an extra argument that does nothing except help resolve the overload. A sort-of similar situation occurs in C++ when you define pre- and post-increment operators for a class. The pre-increment method is declared as `operator++()` while the post-increment must be declared as `operator++(int)`. The `int` argument doesn’t do anything except giving the two methods different signatures.

---

<div class="post-metadata">

**Author:** ![Carltoffel](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/carltoffel/32/1680_2.png) [@Carltoffel](https://fortran-lang.discourse.group/u/Carltoffel)\
**Post date:** [July 20, 2023, 9:08am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/18 "2023-07-20T09:08:36Z")

</div>

Is there a way to detect unallocated variables, if I don’t know if it is an allocatable variable?

---

<div class="post-metadata">

**Author:** ![mEm](https://avatars.discourse-cdn.com/v4/letter/m/90ced4/32.png) [@mEm](https://fortran-lang.discourse.group/u/mEm)\
**Post date:** [July 20, 2023, 9:23am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/19 "2023-07-20T09:23:02Z")

</div>

You mean when passed as argument to a procedure ?

Maybe use the `optional` attribute:

```auto
program main
   implicit none
   integer, target :: ints(4) = [1, 2, 3, 4]
   integer, allocatable, target :: iall(:)
   integer, pointer :: iptr(:) => null()

   call checkAlloc(1)
   call checkAlloc(ints)
   iptr => iall
   call checkAlloc(iall)
   call checkAlloc(iptr)
   allocate(iall(2))
   call checkAlloc(iall)
   call checkAlloc(iptr)
contains
   subroutine checkAlloc(var)
      integer, optional :: var(..)

      if (present(var)) then
         print *, ' Var is "allocated"'
         return
      endif
      print *, ' Var is NOT "allocated"'
   end subroutine
end program main

```

---

<div class="post-metadata">

**Author:** ![Carltoffel](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/carltoffel/32/1680_2.png) [@Carltoffel](https://fortran-lang.discourse.group/u/Carltoffel)\
**Post date:** [July 20, 2023, 9:34am UTC](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114/20 "2023-07-20T09:34:52Z")

</div>

Thanks, this should work in my case. But I was confused why the last `call checkAlloc(iptr)` says it’s NOT allocated. It’s because you have to associate the pointer **after** `iall` was allocated.

[Next page](https://fortran-lang.discourse.group/t/how-to-have-a-generic-interface-for-both-allocatable-and-non-allocatable-dummy/6114.md?page=2)
