Skip to content

Commit 0fd78fa

Browse files
committed
document inheritance support and current limitations
1 parent 4be5de4 commit 0fd78fa

5 files changed

Lines changed: 90 additions & 4 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@ release tags add a leading `v` to the package version.
5555
- Refreshed the README and website around the canonical
5656
**PRIK — Python Runtime Interop Kit** identity, with a concise FAQ, a fair
5757
PRIK-versus-f2py guide, clearer array guidance, and searchable real-library
58-
examples, including a four-library capability and validation summary.
58+
examples, including a four-library capability and validation summary, a
59+
concise statement of current limitations, and a derived-type inheritance
60+
walkthrough.
5961
- Hardened preprocessing, compiler-derived type probes, semantic policy
6062
completion, and multi-source build reporting so unsupported contracts fail
6163
earlier with clearer diagnostics.

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ the user guide, examples, and reference material.
3737
- [See it in action](#see-it-in-action)
3838
- [Key Features](#key-features)
3939
- [Performance](#performance)
40+
- [Current limitations](#current-limitations)
4041
- [Installation & Quick Start](#installation--quick-start)
4142
- [How it works](#how-it-works)
4243
- [Native Project Inputs](#native-project-inputs)
@@ -156,6 +157,16 @@ charts below come from the latest successfully deployed benchmark snapshot.
156157

157158
[See the complete results, test environment, and one-command reproduction instructions.](https://pynumlab.github.io/prik/user/performance/)
158159

160+
## Current limitations
161+
162+
PRIK does not yet support:
163+
164+
- arrays of derived types;
165+
- procedure pointers, including procedure-pointer module variables and callbacks
166+
retained after the wrapped call; or
167+
- polymorphic outputs, mutable polymorphic arguments, polymorphic arrays,
168+
unlimited polymorphism (`class(*)`), abstract types, and deferred bindings.
169+
159170
## Installation & Quick Start
160171

161172
PRIK requires **Python 3.10 or newer**, NumPy, Python development headers,

docs/user/guide/wrapping-derived-types.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,78 @@ For the complete mapping rules, see
250250

251251
---
252252

253+
## Inheritance And Polymorphic Input Dispatch
254+
255+
Fortran extension types generate a matching Python inheritance hierarchy.
256+
Inherited fields and methods remain available on the derived class, and an
257+
overridden type-bound method uses the derived implementation.
258+
259+
```fortran
260+
type :: base_shape
261+
real(8) :: size
262+
contains
263+
procedure :: area => base_area
264+
procedure :: set_size => base_set_size
265+
end type base_shape
266+
267+
type, extends(base_shape) :: circle
268+
real(8) :: radius
269+
contains
270+
procedure :: area => circle_area
271+
end type circle
272+
273+
contains
274+
275+
real(8) function base_area(self) result(value)
276+
class(base_shape), intent(in) :: self
277+
value = self%size
278+
end function base_area
279+
280+
subroutine base_set_size(self, value)
281+
class(base_shape), intent(inout) :: self
282+
real(8), intent(in) :: value
283+
self%size = value
284+
end subroutine base_set_size
285+
286+
real(8) function circle_area(self) result(value)
287+
class(circle), intent(in) :: self
288+
value = acos(-1.0_8) * self%radius * self%radius
289+
end function circle_area
290+
```
291+
292+
For a wrapped module imported as `shapes`, the generated classes preserve that
293+
relationship:
294+
295+
```python
296+
shape = shapes.circle()
297+
assert isinstance(shape, shapes.base_shape)
298+
299+
shape.set_size(np.float64(5.0))
300+
shape.radius = np.float64(2.0)
301+
print(shape.size) # inherited field: 5.0
302+
print(shape.area()) # overridden method: about 12.5664
303+
```
304+
305+
A required scalar `class(base), intent(in)` argument accepts wrapped instances
306+
from the known base and descendant classes:
307+
308+
```fortran
309+
real(8) function describe_shape(item) result(value)
310+
class(base_shape), intent(in) :: item
311+
value = item%area()
312+
end function describe_shape
313+
```
314+
315+
```python
316+
print(shapes.describe_shape(shape)) # about 12.5664
317+
```
318+
319+
This polymorphic boundary is intentionally limited to required scalar inputs.
320+
Polymorphic outputs, mutable arguments, arrays, allocatable or pointer scalars,
321+
and unlimited polymorphism (`class(*)`) are not supported.
322+
323+
---
324+
253325
## Type-Bound Generics
254326

255327
A type-bound generic groups several concrete methods under one Python method.

tests/fortran/derived_types/end_to_end/fixtures/finheritance_f90.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ end subroutine base_set_size
3737
real(8) function circle_area(self) result(value)
3838
class(circle), intent(in) :: self
3939

40-
value = self%size + self%radius * self%radius
40+
value = acos(-1.0_8) * self%radius * self%radius
4141
end function circle_area
4242

4343
real(8) function box_area(self) result(value)

tests/fortran/derived_types/end_to_end/test_inheritance_and_polymorphism.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ def test_fortran_extension_types_generate_python_inheritance(
4444
circle.set_size(np.float64(5.0))
4545
circle.radius = np.float64(2.0)
4646
assert circle.size == np.float64(5.0)
47-
assert circle.area() == np.float64(9.0)
48-
assert module.describe_shape(circle) == np.float64(9.0)
47+
expected_circle_area = np.float64(np.pi * circle.radius**2)
48+
np.testing.assert_allclose(circle.area(), expected_circle_area)
49+
np.testing.assert_allclose(module.describe_shape(circle), expected_circle_area)
4950

5051
module.base_shape.set_size(circle, np.float64(7.0))
5152
assert circle.size == np.float64(7.0)

0 commit comments

Comments
 (0)