Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Break Type Derivation module into chapters #471

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
480 changes: 40 additions & 440 deletions courses/fundamentals_of_ada/075_type_derivation.rst

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
==============
Introduction
==============

-----------------
Type Derivation
-----------------

* Type :dfn:`derivation` allows for reusing code
* Type can be **derived** from a **base type**
* Base type can be substituted by the derived type
* Subprograms defined on the base type are **inherited** on derived type
* This is **not** OOP in Ada

- Tagged derivation **is** OOP in Ada

---------------------------
Reminder: What is a Type?
---------------------------

* A type is characterized by two elements

- Its data structure
- The set of operations that applies to it

* The operations are called **primitive operations** in Ada

.. container:: latex_environment small

.. code:: Ada

package Types is
type Integer_T is range -(2**63) .. 2**63-1 with Size => 64;
procedure Increment_With_Truncation (Val : in out Integer_T);
procedure Increment_With_Rounding (Val : in out Integer_T);
end Types;

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
===================
Simple Derivation
===================

------------------------
Simple Type Derivation
------------------------

* Any type (except :ada:`tagged`) can be derived

.. code:: Ada

type Natural_T is new Integer_T range 0 .. Integer_T'Last;

* :ada:`Natural_T` inherits from:

- The data **representation** of the parent

* Integer based, 64 bits

- The **primitives** of the parent

* :ada:`Increment_With_Truncation` and :ada:`Increment_With_Rounding`

* The types are not the same

.. code:: Ada

I_Obj : Integer_T := 0;
N_Obj : Natural_T := 0;

* :ada:`I_Obj := N_Obj;` |rightarrow| generates a compile error

:color-red:`expected type "Integer_T" defined at line 2`

* But a child can be converted to the parent

* :ada:`I_Obj := Integer_T (N_Obj);`

--------------------------------------
Simple Derivation and Type Structure
--------------------------------------

* The type "structure" can not change

- :ada:`array` cannot become :ada:`record`
- Integers cannot become floats

* But can be **constrained** further
* Scalar ranges can be reduced

.. code:: Ada

type Positive_T is new Natural_T range 1 .. Natural_T'Last;

* Unconstrained types can be constrained

.. code:: Ada

type Arr_T is array (Integer range <>) of Integer;
type Ten_Elem_Arr_T is new Arr_T (1 .. 10);
type Rec_T (Size : Integer) is record
Elem : Arr_T (1 .. Size);
end record;
type Ten_Elem_Rec_T is new Rec_T (10);

163 changes: 163 additions & 0 deletions courses/fundamentals_of_ada/075_type_derivation/03-primitives.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
============
Primitives
============

--------------------
Primitive Operations
--------------------

* Primitive Operations are those subprograms associated with a type

.. code:: Ada

type Integer_T is range -(2**63) .. 2**63-1 with Size => 64;
procedure Increment_With_Truncation (Val : in out Integer_T);
procedure Increment_With_Rounding (Val : in out Integer_T);

* Most types have some primitive operations defined by the language

* e.g. equality operators for most types, numeric operators for integers and floats

* A primitive operation on the parent can receive an object of a child type with no conversion

.. code:: Ada

declare
N_Obj : Natural_T := 1234;
begin
Increment_With_Truncation (N_Obj);
end;

---------------------------------------
General Rule for Defining a Primitive
---------------------------------------

* Primitives are subprograms
* Subprogram :ada:`S` is a primitive of type :ada:`T` if and only if:

- :ada:`S` is declared in the scope of :ada:`T`
- :ada:`S` uses type :ada:`T`

+ As a parameter
+ As its return type (for a :ada:`function`)

- :ada:`S` is above :dfn:`freeze-point` (see next section)

* Standard practice

- Primitives should be declared **right after** the type itself
- In a scope, declare at most a **single** type with primitives

.. code:: Ada

package P is
type T is range 1 .. 10;
procedure P1 (V : T);
procedure P2 (V1 : Integer; V2 : T);
function F return T;
end P;

------------------------------
Primitive of Multiple Types
------------------------------

A subprogram can be a primitive of several types

.. code:: Ada

package P is
type Distance_T is range 0 .. 9999;
type Percentage_T is digits 2 range 0.0 .. 1.0;
type Units_T is (Meters, Feet, Furlongs);

procedure Convert (Value : in out Distance_T;
Source : Units_T;
Result : Units_T;
procedure Shrink (Value : in out Distance_T;
Percent : Percentage_T);

end P;

* :ada:`Convert` and :ada:`Shrink` are primitives for :ada:`Distance_T`
* :ada:`Convert` is also a primitive of :ada:`Units_T`
* :ada:`Shrink` is also a primitive of :ada:`Percentage_T`

----------------------------------
Creating Primitives for Children
----------------------------------

* Just because we can inherit a primitive from out parent doesn't mean we want to

* We can create a new primitive (with the same name as the parent) for the child

* Very similar to overloaded subprograms
* But added benefit of visibility to grandchildren

* We can also remove a primitive (see next slide)

.. code:: Ada

type Integer_T is range -(2**63) .. 2**63-1;
procedure Increment_With_Truncation (Val : in out Integer_T);
procedure Increment_With_Rounding (Val : in out Integer_T);

type Child_T is new Integer_T range -1000 .. 1000;
procedure Increment_With_Truncation (Val : in out Child_T);

type Grandchild_T is new Child_T range -100 .. 100;
procedure Increment_With_Rounding (Val : in out Grandchild_T);

------------------------
Overriding Indications
------------------------

* **Optional** indications
* Checked by compiler

.. container:: latex_environment footnotesize

.. code:: Ada

type Child_T is new Integer_T range -1000 .. 1000;
procedure Increment_With_Truncation
(Val : in out Child_T);
procedure Just_For_Child
(Val : in out Child_T);

* **Replacing** a primitive: :ada:`overriding` indication

.. container:: latex_environment footnotesize

.. code:: Ada

overriding procedure Increment_With_Truncation
(Val : in out Child_T);

* **Adding** a primitive: :ada:`not overriding` indication

.. container:: latex_environment footnotesize

.. code:: Ada

not overriding procedure Just_For_Child
(Val : in out Child_T);

* **Removing** a primitive: :ada:`overriding` as :ada:`abstract`

.. container:: latex_environment footnotesize

.. code:: Ada

overriding procedure Just_For_Child
(Val : in out Grandchild_T) is abstract;

* Using :ada:`overriding` or :ada:`not overriding` incorrectly will generate a compile error

..
language_version 2005

------
Quiz
------

.. include:: ../quiz/operators_override_simple/quiz.rst
117 changes: 117 additions & 0 deletions courses/fundamentals_of_ada/075_type_derivation/04-freeze_point.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
==============
Freeze Point
==============

-----------------------------
What is the "Freeze Point"?
-----------------------------

* Ada doesn't explicitly identify the end of the "scope" of a type

* The compiler needs to know it for determining primitive operations
* Also needed for other situations (described elsewhere)

* This end is the implicit **freeze point** occurring whenever:

- A **variable** of the type is **declared**
- The type is **derived**
- The **end of the scope** is reached

* Subprograms past this "freeze point" are not primitive operations

.. code:: Ada

type Parent is Integer;
procedure Prim (V : Parent);

type Child is new Parent;

-- Parent has been derived, so it is frozen.
-- Prim2 is not a primitive
procedure Prim2 (V : Parent);

V : Child;

-- Child used in an object declaration, so it is frozen
-- Prim3 is not a primitive
procedure Prim3 (V : Child);

-----------------------
Debugging Type Freeze
-----------------------

* Freeze |rightarrow| Type **completely** defined
* Compiler does **need** to determine the freeze point

- To instantiate, derive, get info on the type (:ada:`'Size`)...
- Freeze rules are a guide to place it
- Actual choice is more technical

+ May contradict the standard

* :command:`-gnatDG` to get **expanded** source

- **Pseudo-Ada** debug information

:filename:`pkg.ads`

.. code:: Ada

type Up_To_Eleven is range 0 .. 11;

:filename:`<obj>/pkg.ads.dg`

.. container:: latex_environment tiny

::

type example__up_to_eleven_t is range 0 .. 11; -- type declaration
[type example__Tup_to_eleven_tB is new short_short_integer] -- representation
freeze example__Tup_to_eleven_tB [] -- freeze representation
freeze example__up_to_eleven_t [] -- freeze representation

------
Quiz
------

.. container:: latex_environment tiny

.. code:: Ada

type Parent is range 1 .. 100;
procedure Proc_A (X : in out Parent);

type Child is new Parent range 2 .. 99;
procedure Proc_B (X : in out Parent);
procedure Proc_B (X : in out Child);

-- Other scope
procedure Proc_C (X : in out Child);

type Grandchild is new Child range 3 .. 98;

procedure Proc_C (X : in out Grandchild);

.. container:: columns

.. container:: column

Which are :ada:`Parent`'s primitives?

A. :answermono:`Proc_A`
B. ``Proc_B``
C. ``Proc_C``
D. No primitives of :ada:`Parent`

.. container:: column

.. container:: animate

Explanations

A. Correct
B. Freeze: :ada:`Parent` has been derived
C. Freeze: scope change
D. Incorrect


Loading
Loading