Skip to content

Commit 7dd001d

Browse files
committed
Add rfc for inference of formals
1 parent 7218fa1 commit 7dd001d

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
- Feature Name: Inference of dependent types in generic instantiations
2+
- Start Date: 2023-03-03
3+
- RFC PR: (leave this empty)
4+
- RFC Issue: (leave this empty)
5+
6+
Summary
7+
=======
8+
9+
This RFC proposes to allow inference of types in generic specification, when
10+
there is a way to deduce it from other generic parameters.
11+
12+
Motivation
13+
==========
14+
15+
This RFC is part of the bigger high-level RFC about improving generic
16+
instantiations ([here](../meta/rfc-improved-generic-instantiations.md)), so the
17+
need arises from that context, and it's useful to go read the high level RFC to
18+
understand the bigger picture.
19+
20+
However, even in the reduced context of explicit instantiations, it's easy to
21+
understand the value of this feature with a few simple examples:
22+
23+
```ada
24+
type Integer_Access is access all Integer;
25+
26+
procedure Free is new Unchecked_Deallocation (Name => Integer_Access);
27+
```
28+
29+
or
30+
31+
```ada
32+
type Arr is array (Positive range <>) of Integer;
33+
34+
package Int_Array_Sort
35+
is new Ada.Containers.Generic_Array_Sort (Array_Type => Arr);
36+
```
37+
38+
or
39+
40+
```ada
41+
```
42+
43+
Guide-level explanation
44+
=======================
45+
46+
In every case where a generic formal references other types, those types can
47+
be other formal types. In those case, the user of the generic needs to pass
48+
every type separately.
49+
50+
51+
```ada
52+
generic
53+
type Element_Type is private;
54+
type Index_Type is (<>);
55+
type Array_Type is array (Index_Type range <>) of Element_Type;
56+
package Array_Operations is
57+
...
58+
end Array_Operations;
59+
60+
...
61+
62+
type Int_Array is array (Positive range <>) of Integer;
63+
64+
package Int_Array_Operations is new Array_Operations
65+
(Element_Type => Integer,
66+
Index_Type => Positive,
67+
Array_Type => Int_Array);
68+
```
69+
70+
This feature allows the programmer to not have to pass type parameters that
71+
could be deduced from other type parameters. In the example above, the language
72+
can automatically deduce the index and element type from the array type that is
73+
passed in:
74+
75+
```ada
76+
package Int_Array_Operations is new Array_Operations (Array_Type => Int_Array);
77+
```
78+
79+
* Generic formal array types (see the first example)
80+
81+
* Generic formal access types, where the accessed type can be deduced from the
82+
access type.
83+
84+
```ada
85+
type Integer_Access is access all Integer;
86+
87+
procedure Free is new Unchecked_Deallocation (Name => Integer_Access);
88+
```
89+
90+
* Generic formal subprograms, where any type can be deduced from the type of
91+
the formals of the subprogram
92+
93+
```ada
94+
generic
95+
type Element_Type is private;
96+
type Array_Type is array (Positive range <>) of Element_Type;
97+
type Key_Type is private;
98+
with function Key (E : Element_Type) return Key_Type;
99+
with function "<" (L, R : Key_Type) return Boolean is (<>);
100+
function Min_By (Self : Array_Type) return Element_Type;
101+
102+
-- usage:
103+
104+
type Person is record
105+
Name : Unbounded_String;
106+
Age : Natural;
107+
end record;
108+
109+
function Age_Of (P : Person) return Natural is (P.Age);
110+
111+
type Person_Array is array (Positive range <>) of Person;
112+
113+
function Min_By_Age is new Min_By
114+
(Array_Type => Person_Array, Key => Age_Of);
115+
-- Element_Type inferred from Person_Array, Key_Type inferred from Age_Of
116+
117+
DB : Person_Array := ...;
118+
Younger : Person := Min_By_Age (DB);
119+
```
120+
121+
> **Note**
122+
> We decided to not include generic formal packages, because the implementer
123+
> already has the option to not require the user to pass in the dependent
124+
> types, via the `<>` syntax:
125+
>
126+
> ```ada
127+
> generic
128+
> with package P is new Q (<>);
129+
> ```
130+
131+
Reference-level explanation
132+
===========================
133+
134+
To be completed
135+
136+
### Syntax changes
137+
138+
No syntax changes planned
139+
140+
### Semantic changes
141+
142+
When in the presence of a dependent type, as defined above, in a generic
143+
formal, the instantiator of the generic can omit this type, either passing `<>`
144+
explicitly, or just omitting it from the instantiation completely.
145+
146+
The compiler will deduce it from other parameters.
147+
148+
Rationale and alternatives
149+
==========================
150+
151+
The rationale is contained in the high level RFC on generics.
152+
153+
As far as alternatives go, we could imagine a world where developers don't even
154+
have to specify the dependent formals:
155+
156+
```ada
157+
generic
158+
type Array_Type is array (<>) of <>;
159+
package Array_Operations is
160+
subtype Index_Type is Array_Type'Index_Type;
161+
subtype Element_Type is Array_Type'Element_Type;
162+
end Array_Operations;
163+
164+
...
165+
166+
type Int_Array is array (Positive range <>) of Integer;
167+
168+
package Int_Array_Operations is new Array_Operations
169+
(Array_Type => Int_Array);
170+
```
171+
172+
However, the current alternative has the advantage of being backwards
173+
compatible with existing generic declarations.
174+
175+
176+
Drawbacks
177+
=========
178+
179+
N/A
180+
181+
Prior art
182+
=========
183+
184+
This is very specific to Ada's generic formals system, but we could consider
185+
that they way generic formal packages' own params can be deduced when
186+
instantiating the generic, is pretty similar to what we propose here, so that
187+
this is the extension of an already existing mechanism.

meta/rfc-improved-generic-instantiations.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ features.
115115

116116
### First step: Inference of dependent types in generic instantiations
117117

118-
Using the feature described in [this rfc (TODO)](https://todoaddlink),
118+
Using the feature described in [this rfc](../considered/rfc-inference-of-dependent-types.md),
119119
we could then simplify the above code's Reduce instantiation:
120120

121121
```ada
@@ -270,3 +270,13 @@ Many (most) languages with generics have implicit/structural instantiations of
270270
generics. It's on the other hand hard to find languages with explicit
271271
instantiations like Ada. All mainstream languages today use implicit/structural
272272
generics (Java/C++/C#/Rust/Go/etc).
273+
274+
Future possibilities
275+
--------------------
276+
277+
An idea that was pointed out was that we might want to be able to annotate
278+
generics to explicitly forbid structural references to instantiations, for
279+
cases where generics have state that you might not want to implicitly share
280+
between references. One example that comes to mind is GNAT's HTable package.
281+
282+

0 commit comments

Comments
 (0)