|
| 1 | +- Feature Name: Partial instantiation of generics |
| 2 | +- Start Date: 2023-04-11 |
| 3 | +- RFC PR: (leave this empty) |
| 4 | +- RFC Issue: (leave this empty) |
| 5 | + |
| 6 | +Summary |
| 7 | +======= |
| 8 | + |
| 9 | +This RFC builds up on top of [the structural generic instantiation |
| 10 | +RFC](./rfc-structural-generic-instantiation.md), and proposes to be able to |
| 11 | +infer generic actuals for structural generic instantiations, from the actuals |
| 12 | +of the subprogram call, in cases where the structural generic instantiation |
| 13 | +refers to a subprogram. |
| 14 | + |
| 15 | +Motivation |
| 16 | +========== |
| 17 | + |
| 18 | +This RFC is part of the bigger high-level RFC about improving generic |
| 19 | +instantiations ([here](../meta/rfc-improved-generic-instantiations.md)), so the |
| 20 | +need arises from that context, and it's useful to go read the high level RFC to |
| 21 | +understand the bigger picture. |
| 22 | + |
| 23 | +However, unlike other RFCs of that series, this one is pretty orthogonal to the |
| 24 | +rest, and would provide usability benefits even if the rest of the RFCs were |
| 25 | +not to be implemented. |
| 26 | + |
| 27 | +The idea is to be able to create "new" generic specifications from existing |
| 28 | +ones, by just specifying a subset of their parameters. This would simplify some |
| 29 | +uses of generics, and would make creating "specialized" instances much easier. |
| 30 | + |
| 31 | +Guide-level explanation |
| 32 | +======================= |
| 33 | + |
| 34 | +The idea is to be able to create "new" generic specifications from existing |
| 35 | +ones, by just specifying a subset of their parameters. |
| 36 | + |
| 37 | +Here is an example with `Ada.Containers.Vectors`: |
| 38 | + |
| 39 | +```ada |
| 40 | +generic |
| 41 | + type Index_Type is range <>; |
| 42 | + type Element_Type is private; |
| 43 | +
|
| 44 | + with function "=" (Left : in Element_Type; |
| 45 | + Right : in Element_Type) |
| 46 | + return Boolean is <>; |
| 47 | +
|
| 48 | +package Ada.Containers.Vectors is ... |
| 49 | +
|
| 50 | +generic package Vecs |
| 51 | +is Ada.Containers.Vectors (Index_Type => Positive); |
| 52 | +
|
| 53 | +package Float_Vectors is new Vecs (Float); |
| 54 | +``` |
| 55 | + |
| 56 | +In the above example, the formal part between `generic` and `package` is empty, |
| 57 | +which means that remaining params are infered from the partially instantiated |
| 58 | +specification. |
| 59 | + |
| 60 | +While this can be practical in simple cases: |
| 61 | + |
| 62 | +* We want to let people the ability to fully specify formals |
| 63 | +* We want to allow more complex patterns like reordering/renaming formals |
| 64 | + |
| 65 | +Which leads us to the more complete syntax: |
| 66 | + |
| 67 | +```ada |
| 68 | +generic |
| 69 | + type El_T is private; |
| 70 | + with function "=" (Left : in El_T; Right : in El_T) return Boolean is <>; |
| 71 | +package Vecs is Ada.Containers.Vectors |
| 72 | + (Index_Type => Positive, |
| 73 | + Element_Type => El_T, |
| 74 | + "=" => "="); |
| 75 | +``` |
| 76 | + |
| 77 | +While generic formal parts for standard containers are pretty simple, there |
| 78 | +were experiments by AdaCore with creating much more generic specifications for |
| 79 | +containers, in the `ada-traits-containers` library, and specializations of |
| 80 | +those packages were provided, see for example |
| 81 | +[this](https://github.com/AdaCore/ada-traits-containers/blob/master/src/conts-maps-indef_def_unbounded.ads) |
| 82 | + |
| 83 | +The problem with this pattern is that: |
| 84 | + |
| 85 | +* Entities from the `Impl` package are not automatically forwarded, so |
| 86 | + uses have to go through `Instantiation.Impl.` |
| 87 | + |
| 88 | +* Means of forwarding are explicit (see the renamings/subtypes lower in the |
| 89 | + spec) |
| 90 | + |
| 91 | +Using structural instantiations together with partial instantiations from this |
| 92 | +RFC, and anonymous subprograms, one could write: |
| 93 | + |
| 94 | +```ada |
| 95 | +generic |
| 96 | + type Key_Type (<>) is private; |
| 97 | + type Element_Type is private; |
| 98 | + type Container_Base_Type is abstract tagged limited private; |
| 99 | + with function Hash (Key : Key_Type) return Hash_Type; |
| 100 | + with function "=" (Left, Right : Key_Type) return Boolean is |
| 101 | + with procedure Free (E : in out Key_Type) is null; |
| 102 | + with procedure Free (E : in out Element_Type) is null; |
| 103 | +package Conts.Maps.Indef_Def_Unbounded is |
| 104 | + Conts.Maps.Generics |
| 105 | + (Keys => Conts.Elements.Indefinite [Key_Type, Conts.Global_Pool, Free].Traits, |
| 106 | + Elements => Conts.Elements.Definite [Element_Type, Free => Free].Traits, |
| 107 | + Hash => Hash, |
| 108 | + "=" => |
| 109 | + function (Left : Key_Type; Right : Keys.Traits.Stored) return Boolean |
| 110 | + is (Left = Right.all), |
| 111 | + Probing => Conts.Maps.Perturbation_Probing, |
| 112 | + Pool => Conts.Global_Pool, |
| 113 | + Container_Base_Type => Container_Base_Type); |
| 114 | +``` |
| 115 | + |
| 116 | +Alternatively, if we consider that having "inline" syntax for sub-elements is a |
| 117 | +problem - for example, because for anonymous functions, it doesn't exist yet - |
| 118 | +we can introduce a syntax to introduce declarations inbetween the formal part |
| 119 | +and the partial instantiation: |
| 120 | + |
| 121 | +```ada |
| 122 | +generic |
| 123 | + type Key_Type (<>) is private; |
| 124 | + type Element_Type is private; |
| 125 | + type Container_Base_Type is abstract tagged limited private; |
| 126 | + with function Hash (Key : Key_Type) return Hash_Type; |
| 127 | + with function "=" (Left, Right : Key_Type) return Boolean is <>; |
| 128 | + with procedure Free (E : in out Key_Type) is null; |
| 129 | + with procedure Free (E : in out Element_Type) is null; |
| 130 | +declare |
| 131 | + package Keys is new Conts.Elements.Indefinite |
| 132 | + (Key_Type, Pool => Conts.Global_Pool, Free => Free); |
| 133 | + package Elements is new Conts.Elements.Definite |
| 134 | + (Element_Type, Free => Free); |
| 135 | + function "=" (Left : Key_Type; Right : Keys.Traits.Stored) return Boolean |
| 136 | + is (Left = Right.all) with Inline; |
| 137 | +package Conts.Maps.Indef_Def_Unbounded is Conts.Maps.Generics |
| 138 | + (Keys => Keys.Traits, |
| 139 | + Elements => Elements.Traits, |
| 140 | + Hash => Hash, |
| 141 | + "=" => "=", |
| 142 | + Probing => Conts.Maps.Perturbation_Probing, |
| 143 | + Pool => Conts.Global_Pool, |
| 144 | + Container_Base_Type => Container_Base_Type); |
| 145 | +``` |
| 146 | + |
| 147 | +Reference-level explanation |
| 148 | +=========================== |
| 149 | + |
| 150 | +TBD |
| 151 | + |
| 152 | +Rationale and alternatives |
| 153 | +========================== |
| 154 | + |
| 155 | +The rationale is contained in the high level RFC on generics. |
| 156 | + |
| 157 | +Drawbacks |
| 158 | +========= |
| 159 | + |
| 160 | +N/A |
| 161 | + |
| 162 | +Prior art |
| 163 | +========= |
| 164 | + |
| 165 | +TBD |
0 commit comments