Self-Assessment Quiz: Object-Oriented Fortran
Twenty questions on the mechanics and the judgment. This is an advanced chapter; aim for 16 or more. Answers and a topic map are at the end — try the whole quiz first, and predict the code outputs by hand.
Question 1
type, extends(shape_t) :: circle_t makes circle_t:
- A. A copy of shape_t with a different name
- B. A type that inherits shape_t's components and bindings and may add or override
- C. A pointer to a shape_t
- D. An alias for shape_t
Question 2
The difference between type(shape_t) and class(shape_t) is:
- A. None; they are synonyms
- B. type is monomorphic (fixed type); class is polymorphic (may hold the type or any extension)
- C. class is faster
- D. type allows inheritance; class does not
Question 3
A polymorphic local variable class(shape_t) :: s (not a dummy argument) is:
- A. Always allowed
- B. Allowed only if it is allocatable or pointer
- C. Allowed only for abstract types
- D. Never allowed under any circumstances
Question 4
In select type, type is (circle_t) matches when the dynamic type is:
- A. circle_t or any extension of it
- B. Exactly circle_t
- C. Any shape
- D. shape_t only
Question 5
class is (rectangle_t) matches when the dynamic type is:
- A. Exactly rectangle_t
- B. rectangle_t or any type that extends it
- C. Any type at all
- D. Only abstract types
Question 6
An abstract type:
- A. Can be instantiated with type(...)
- B. Cannot be instantiated; it exists only to be extended
- C. Cannot have components
- D. Cannot be extended
Question 7
A deferred binding:
- A. Provides a default implementation
- B. Names a binding with no body that every concrete extension must implement
- C. Is called only at program exit
- D. Is a synonym for final
Question 8
Inside an abstract interface body, you must import the host's derived types because:
- A. import is faster than use
- B. The interface body is a separate scoping unit and does not automatically see host entities
- C. Abstract types cannot be named
- D. It is optional stylistic sugar
Question 9
A final procedure's dummy argument must be declared:
- A. class(t), intent(inout)
- B. type(t), intent(inout)
- C. class(t), intent(in)
- D. type(t), intent(out)
Question 10
A final procedure runs:
- A. When you call it explicitly
- B. Automatically, just before an object of its type is destroyed
- C. Only for pointer variables
- D. At the start of every procedure
Question 11
To store a mix of circle_t and rectangle_t values in one array, you should:
- A. Use class(shape_t), allocatable :: arr(:)
- B. Use an array of a small derived type that wraps class(shape_t), allocatable :: obj
- C. Use type(shape_t) :: arr(:)
- D. It is impossible in Fortran
Question 12
Why can't class(shape_t), allocatable :: arr(:) hold a mix of dynamic types?
- A. Arrays cannot be allocatable
- B. Every element of a polymorphic array must share one dynamic type
- C. class is not allowed for arrays
- D. It can — the premise is false
Question 13
The single most important performance rule of this chapter is:
- A. Always use class instead of type
- B. Put polymorphism at the coarse grain (which solver), never in the hot inner loop (per cell)
- C. Never use modules with OOP
- D. Finalize every object manually
Question 14
A dynamically dispatched call is often slower mainly because: - A. It uses more memory - B. It cannot be inlined, which blocks the optimizer from fusing and vectorizing the call - C. It runs on the GPU - D. It allocates a new object each time
Question 15
Calling the parent's version of an overridden binding from a child is written:
- A. call super%method()
- B. call self%parent_t%method() (via the parent component)
- C. call parent::method()
- D. call method@parent()
Question 16
A long select type chain that implements different behavior per type is usually a sign that:
- A. Your code is well designed
- B. You should have used a deferred binding so each type carries its own behavior
- C. You need more class default blocks
- D. Polymorphism is impossible here
Question 17
Object orientation arrived in which Fortran standard? - A. FORTRAN 77 - B. Fortran 95 - C. Fortran 2003 - D. Fortran 2018
Question 18 (what does it print?)
Using the abstract hierarchy, with a rectangle of width 3 and height 4:
class(shape_t), allocatable :: s
allocate(s, source = rectangle_t(width = 3.0_dp, height = 4.0_dp))
print '(f6.2)', s%area()
- A.
12.00 - B.
0.00 - C. A compile error
- D.
7.00
Question 19 (true/false + justify)
True or false: "Because allocatable components are deallocated automatically when their containing object is
destroyed, you usually do not need a final procedure to free them."
Question 20 (short answer)
In the solver_t framework, the driver holds a class(solver_t) and calls sim%step(plate) once per
timestep. State (a) where the dynamic dispatch happens and (b) why placing it there, rather than inside the
per-cell loop, is the correct design.
Answer Key
| Q | Ans | Why |
|---|---|---|
| 1 | B | extends inherits components and bindings; the child may add and override. |
| 2 | B | type is monomorphic; class is polymorphic (declared vs dynamic type may differ). |
| 3 | B | A polymorphic non-dummy object needs indirection: allocatable or pointer. |
| 4 | B | type is matches the exact dynamic type. |
| 5 | B | class is matches that type or any extension. |
| 6 | B | Abstract types cannot be instantiated; they are extended. |
| 7 | B | A deferred binding is a contract every concrete extension must fulfill. |
| 8 | B | The interface body is its own scoping unit; import brings host names in. |
| 9 | B | A finalizer takes type(...), intent(inout) — it is not dispatched. |
| 10 | B | It runs automatically just before destruction (deallocate/scope exit/overwrite). |
| 11 | B | Wrap the polymorphic value in a box type and make an array of boxes. |
| 12 | B | A polymorphic array is uniform: one dynamic type for all elements. |
| 13 | B | Coarse-grained polymorphism only; never dispatch per cell in a hot loop. |
| 14 | B | An indirect call can't be inlined, which blocks fusion and vectorization. |
| 15 | B | Reach the parent through the parent component: self%parent_t%method(). |
| 16 | B | Per-type behavior belongs in a deferred binding, not a maintained chain. |
| 17 | C | Fortran 2003 made the language object-oriented. |
| 18 | A | rectangle_area returns $3\times4=12$; f6.2 prints 12.00. |
| 19 | True | Allocatable components self-deallocate; final is for unmanaged resources (files, C memory). |
| 20 | — | (a) At sim%step — one dispatch per timestep. (b) It is amortized over the whole grid update, so it costs nothing, while the per-cell arithmetic stays monomorphic, inlinable, and vectorizable. |
Topics to review by question
- Q1, Q15 → §10.1 (type extension, calling the parent).
- Q2, Q3, Q11, Q12 → §10.2 (
classvstype, polymorphic arrays and the box idiom). - Q4, Q5, Q16 → §10.3 (
select type; the design-smell warning). - Q6–Q10, Q19 → §10.4 (abstract, deferred,
import,final). - Q13, Q14, Q20 → §10.5 and §10.6 (when OOP hurts; keep dispatch coarse-grained).
- Q17 → §10.1 (from history: OOP in Fortran 2003).
- Q18 → §10.4 (dispatch through an abstract type).
Scored below 16? Re-read §10.2 (the class/type distinction and the box idiom) and §10.5 (the
performance rule) — those two carry the chapter, and both return in Part VII and Part VIII.