From 308730116b4098d1c43937d2452f19cecd649b96 Mon Sep 17 00:00:00 2001 From: Michael Frank <55284511+frank-at-adacore@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:31:01 -0500 Subject: [PATCH 01/11] Break Introduction module into chapters --- .../fundamentals_of_ada/005_introduction.rst | 176 ++++-------------- .../005_introduction/01-about_adacore.rst | 21 +++ .../02-about_this_training.rst | 83 +++++++++ 3 files changed, 141 insertions(+), 139 deletions(-) create mode 100644 courses/fundamentals_of_ada/005_introduction/01-about_adacore.rst create mode 100644 courses/fundamentals_of_ada/005_introduction/02-about_this_training.rst diff --git a/courses/fundamentals_of_ada/005_introduction.rst b/courses/fundamentals_of_ada/005_introduction.rst index 284dcf418..a8b792212 100644 --- a/courses/fundamentals_of_ada/005_introduction.rst +++ b/courses/fundamentals_of_ada/005_introduction.rst @@ -1,139 +1,37 @@ -************ -Introduction -************ - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============= -About AdaCore -============= - ------------ -The Company ------------ - -.. - Taken from https://www.adacore.com/company/about - -* Founded in 1994 -* Centered around helping developers build **safe, secure and reliable** software -* Headquartered in New York and Paris - - - Representatives in countries around the globe - -* Roots in Open Source software movement - - - GNAT compiler is part of GNU Compiler Collection (GCC) - -=================== -About This Training -=================== - --------------------------- -Your Trainer --------------------------- - -* Experience in software development - - - Languages - - Methodology - -* Experience teaching this class - ------------------------------ -Goals of the training session ------------------------------ - -* What you should know by the end of the training -* Syllabus overview - - - The syllabus is a guide, but we might stray off of it - - ...and that's OK: we're here to cover **your needs** - ----------- -Roundtable ----------- - -* 5 minute exercise - - - Write down your answers to the following - - Then share it with the room - -* Experience in software development - - - Languages - - Methodology - -* Experience and interest with the syllabus - - - Current and upcoming projects - - Curious for something? - -* Your personal goals for this training - - - What do you want to have coming out of this? - -* Anecdotes, stories... feel free to share! - - - Most interesting or funny bug you've encountered? - - Your own programming interests? - -------------------- -Course Presentation -------------------- - -* Slides -* Quizzes -* Labs - - - Hands-on practice - - Recommended setup: latest GNAT Studio - - Class reflection after some labs - -* Demos - - - Depending on the context - -* Daily schedule - --------- -Styles --------- - -* :dfn:`This` is a definition -* :filename:`this/is/a.path` -* :ada:`code is highlighted` -* :command:`commands are emphasised --like-this` - -.. warning:: This is a warning -.. note:: This is an important piece of info -.. tip:: This is a tip +************ +Introduction +************ + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 005_introduction/01-about_adacore.rst +.. include:: 005_introduction/02-about_this_training.rst diff --git a/courses/fundamentals_of_ada/005_introduction/01-about_adacore.rst b/courses/fundamentals_of_ada/005_introduction/01-about_adacore.rst new file mode 100644 index 000000000..24d52ae24 --- /dev/null +++ b/courses/fundamentals_of_ada/005_introduction/01-about_adacore.rst @@ -0,0 +1,21 @@ +============= +About AdaCore +============= + +----------- +The Company +----------- + +.. + Taken from https://www.adacore.com/company/about + +* Founded in 1994 +* Centered around helping developers build **safe, secure and reliable** software +* Headquartered in New York and Paris + + - Representatives in countries around the globe + +* Roots in Open Source software movement + + - GNAT compiler is part of GNU Compiler Collection (GCC) + diff --git a/courses/fundamentals_of_ada/005_introduction/02-about_this_training.rst b/courses/fundamentals_of_ada/005_introduction/02-about_this_training.rst new file mode 100644 index 000000000..81b578774 --- /dev/null +++ b/courses/fundamentals_of_ada/005_introduction/02-about_this_training.rst @@ -0,0 +1,83 @@ +=================== +About This Training +=================== + +-------------------------- +Your Trainer +-------------------------- + +* Experience in software development + + - Languages + - Methodology + +* Experience teaching this class + +----------------------------- +Goals of the training session +----------------------------- + +* What you should know by the end of the training +* Syllabus overview + + - The syllabus is a guide, but we might stray off of it + - ...and that's OK: we're here to cover **your needs** + +---------- +Roundtable +---------- + +* 5 minute exercise + + - Write down your answers to the following + - Then share it with the room + +* Experience in software development + + - Languages + - Methodology + +* Experience and interest with the syllabus + + - Current and upcoming projects + - Curious for something? + +* Your personal goals for this training + + - What do you want to have coming out of this? + +* Anecdotes, stories... feel free to share! + + - Most interesting or funny bug you've encountered? + - Your own programming interests? + +------------------- +Course Presentation +------------------- + +* Slides +* Quizzes +* Labs + + - Hands-on practice + - Recommended setup: latest GNAT Studio + - Class reflection after some labs + +* Demos + + - Depending on the context + +* Daily schedule + +-------- +Styles +-------- + +* :dfn:`This` is a definition +* :filename:`this/is/a.path` +* :ada:`code is highlighted` +* :command:`commands are emphasised --like-this` + +.. warning:: This is a warning +.. note:: This is an important piece of info +.. tip:: This is a tip From ee4efc80e4fe98aadd45d31b21a627fa32a5c9c2 Mon Sep 17 00:00:00 2001 From: Michael Frank <55284511+frank-at-adacore@users.noreply.github.com> Date: Mon, 9 Dec 2024 11:33:50 -0500 Subject: [PATCH 02/11] Comment out debug code in filter --- pandoc/beamer_filter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandoc/beamer_filter.py b/pandoc/beamer_filter.py index 0b737d314..07f6e4599 100755 --- a/pandoc/beamer_filter.py +++ b/pandoc/beamer_filter.py @@ -590,8 +590,8 @@ def format_note(classes, contents): def remove_title(c): # pandoc adds a title element for some admonitions. Remove it. if isinstance(c, list) and len(c) > 0: - with open("toto.py", "at") as f: - print(repr(c), file=f) + # with open("toto.py", "at") as f: + # print(repr(c), file=f) if c[0]["t"] == "Div": if c[0]["c"][0][1][0] == "title": del c[0] From 8974090bf898b280fe0c088448e951013e7fd68b Mon Sep 17 00:00:00 2001 From: Michael Frank <55284511+frank-at-adacore@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:04:41 -0500 Subject: [PATCH 03/11] Remove debug code --- pandoc/beamer_filter.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pandoc/beamer_filter.py b/pandoc/beamer_filter.py index 07f6e4599..470c8d895 100755 --- a/pandoc/beamer_filter.py +++ b/pandoc/beamer_filter.py @@ -590,8 +590,6 @@ def format_note(classes, contents): def remove_title(c): # pandoc adds a title element for some admonitions. Remove it. if isinstance(c, list) and len(c) > 0: - # with open("toto.py", "at") as f: - # print(repr(c), file=f) if c[0]["t"] == "Div": if c[0]["c"][0][1][0] == "title": del c[0] From 5eeb2f88e3c60736809449b5237283390df172a1 Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Mon, 9 Dec 2024 18:15:13 +0000 Subject: [PATCH 04/11] Resolve "break 010_overview into chapters" --- courses/fundamentals_of_ada/010_overview.rst | 539 ++---------------- .../010_overview/01-a_little_history.rst | 65 +++ .../010_overview/02-big_picture.rst | 317 ++++++++++ .../010_overview/03-setup.rst | 84 +++ 4 files changed, 504 insertions(+), 501 deletions(-) create mode 100644 courses/fundamentals_of_ada/010_overview/01-a_little_history.rst create mode 100644 courses/fundamentals_of_ada/010_overview/02-big_picture.rst create mode 100644 courses/fundamentals_of_ada/010_overview/03-setup.rst diff --git a/courses/fundamentals_of_ada/010_overview.rst b/courses/fundamentals_of_ada/010_overview.rst index 7bda4d487..fc9c99046 100644 --- a/courses/fundamentals_of_ada/010_overview.rst +++ b/courses/fundamentals_of_ada/010_overview.rst @@ -1,501 +1,38 @@ -********** -Overview -********** - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -================== -A Little History -================== - ----------- -The Name ----------- - -* First called DoD-1 -* Augusta Ada Byron, "first programmer" - - - Lord Byron's daughter - - Planned to calculate **Bernouilli's numbers** - - **First** computer program - - On **Babbage's Analytical Engine** - -* International Standards Organization standard - - - Updated about every 10 years - -* Writing **ADA** is like writing **CPLUSPLUS** - --------------------------- -Ada Evolution Highlights --------------------------- - -.. container:: columns - - .. container:: column - - .. container:: latex_environment footnotesize - - **Ada 83** - | Abstract Data Types - | Modules - | Concurrency - | Generics - | Exceptions - | - - **Ada 95** - | OOP - | Child Packages - | Annexes - | - - **Ada 2005** - | Multiple Inheritance - | Containers - | Ravenscar - - .. container:: column - - .. container:: latex_environment footnotesize - - **Ada 2012** - | Contracts - | Iterators - | Flexible Expressions - | - - **Ada 2022** - | :ada:`'Image` for all types - | Declare expression - -============= -Big Picture -============= - ---------------------------------------- -Language Structure (Ada95 and Onward) ---------------------------------------- - -* **Required** :dfn:`Core` implementation - - - Reference Manual (RM) sections 1 :math:`\rightarrow` 13 - - Predefined Language Environment (Annex A) - - Interface to Other Languages (Annex B) - - Obsolescent Features (Annex J) - -* Optional :dfn:`Specialized Needs Annexes` - - - No additional syntax - - Systems Programming (C) - - Real-Time Systems (D) - - Distributed Systems (E) - - Information Systems (F) - - Numerics (G) - - High-Integrity Systems (H) - -------------------------- -*Core* Language Content -------------------------- - -* Ada is a **compiled**, **multi-paradigm** language -* With a **static** and **strong** type model - -.. container:: columns - - .. container:: column - - * Language-defined types, including string - * User-defined types - * Overloading procedures and functions - * Compile-time visibility control - * Abstract Data Types (ADT) - - .. container:: column - - * Exceptions - * Generic units - * Dynamic memory management - * Low-level programming - * Object-Oriented Programming (OOP) - * Concurrent programming - * Contract-Based Programming - --------------------------- -The Type Model Saves Money --------------------------- - -* Shifts fixes and costs to **early phases** - - -* Cost of an error *during a flight*? - -.. image:: relative_cost_to_fix_bugs.jpg - :height: 50% - -------------- -Subprograms -------------- - -- Syntax differs between *values* and *actions* -- :ada:`function` for a *value* - -.. code:: Ada - - function Is_Leaf (T : Tree) return Boolean - -- :ada:`procedure` for an *action* - -.. code:: Ada - - procedure Split (T : in out Tree; - Left : out Tree; - Right : out Tree) - -* Specification :math:`\neq` Implementation - - .. code:: Ada - - function Is_Leaf (T : Tree) return Boolean; - function Is_Leaf (T : Tree) return Boolean is - begin - ... - end Is_Leaf; - ---------------------------- -Dynamic Memory Management ---------------------------- - -* Raw pointers are error-prone -* Ada **access types** abstract facility - - - Static memory - - Allocated objects - - Subprograms - -* Accesses are **checked** - - - Unless unchecked mode is used - -* Supports user-defined storage managers - - - Storage **pools** - ----------- -Packages ----------- - -* Grouping of related entities - - - Subsystems like *Fire Control* and *Navigation* - - Common processing like *HMI* and *Operating System* - -* Separation of concerns - - - Specification :math:`\neq` Implementation - - Single definition by **designer** - - Multiple use by **users** - -* Information hiding - - - Compiler-enforced **visibility** - - Powerful **privacy** system - ------------- -Exceptions ------------- - -* Dealing with **errors**, **unexpected** events -* Separate error-handling code from logic -* Some flexibility - - - Re-raising - - Custom messages - ---------------- -Generic Units ---------------- - -.. container:: columns - - .. container:: column - - * Code Templates - - - Subprograms - - Packages - - * Parameterization - - - Strongly typed - - **Expressive** syntax - - .. container:: column - - .. image:: generic_template_to_instances.png - ------------------------------ -Object-Oriented Programming ------------------------------ - -* Inheritance -* Run-time polymorphism -* Dynamic **dispatching** -* Abstract types and subprograms -* **Interface** for multiple inheritance - ----------------------------- -Contract-Based Programming ----------------------------- - -* Pre- and post-conditions -* Formalizes specifications - - .. code:: Ada - - procedure Pop (S : in out Stack) with - Pre => not S.Empty, -- Requirement - Post => not S.Full; -- Guarantee - -* Type invariants - - .. code:: Ada - - type Table is private with Invariant => Sorted (Table); -- Guarantee - --------------------------- -Language-Based Concurrency --------------------------- - -* **Expressive** - - - Close to problem-space - - Specialized constructs - - **Explicit** interactions - -* **Run-time** handling - - - Maps to OS primitives - - Several support levels (Ravenscar...) - -* **Portable** - - - Source code - - People - - OS & Vendors - ------------------------ -Low Level Programming ------------------------ - -* **Representation** clauses -* Bit-level layouts -* Storage pools definition - - - With access safeties - -* Foreign language integration - - - C - - C++ - - Assembly - - etc... - -* Explicit specifications - - - Expressive - - Efficient - - Reasonably portable - - Abstractions preserved - ---------------------------------- -Standard Language Environment ---------------------------------- - -Standardized common API - -.. container:: columns - - .. container:: column - - * Types - - - Integer - - Floating-point - - Fixed-point - - Boolean - - Characters, Strings, Unicode - - etc... - - * Math - - - Trigonometric - - Complexes - - * Pseudo-random number generators - - .. container:: column - - * I/O - - - Text - - Binary (direct / sequential) - - Files - - Streams - - * Exceptions - - - Call-stack - - * **Command-line** arguments - * **Environment** variables - * **Containers** - - - Vector - - Map - ------------------------------- -Language Examination Summary ------------------------------- - -* Unique capabilities -* Three main goals - - - **Reliability**, maintainability - - Programming as a **human** activity - - Efficiency - -* Easy-to-use - - - ...and hard to misuse - - Very **few pitfalls** and exceptions - ------------------------------------ -So Why Isn't Ada Used Everywhere? ------------------------------------ - -.. container:: columns - - .. container:: column - - * "... in all matters of opinion our adversaries are insane" - - - *Mark Twain* - - .. container:: column - - .. image:: mark_twain.jpeg - -======= -Setup -======= - -------------------------- -Canonical First Program -------------------------- - -.. code:: Ada - - 1 with Ada.Text_IO; - 2 -- Everyone's first program - 3 procedure Say_Hello is - 4 begin - 5 Ada.Text_IO.Put_Line ("Hello, World!"); - 6 end Say_Hello; - -* Line 1 - :ada:`with` - Package dependency -* Line 2 - :ada:`--` - Comment -* Line 3 - :ada:`Say_Hello` - Subprogram name -* Line 4 - :ada:`begin` - Begin executable code -* Line 5 - :ada:`Ada.Text_IO.Put_Line ()` - Subprogram call -* (cont) - :ada:`"Hello, World!"` - String literal (type-checked) - ----------------------------------- -"Hello World" Lab - Command Line ----------------------------------- - -* Use an editor to enter the program shown on the previous slide - - - Use your favorite editor or just gedit/notepad/etc. - -* Save and name the file :filename:`say_hello.adb` exactly - - - In a command prompt shell, go to where the new file is located and issue the following command: - - + :command:`gprbuild say_hello` - -* In the same shell, invoke the resulting executable: - - - :command:`say_hello` (Windows) - - :command:`./say_hello` (Linux/Unix) - ---------------------------------------------- -"Hello World" Lab - :toolname:`GNAT Studio` ---------------------------------------------- - -* Start :toolname:`GNAT Studio` from the command-line (:command:`gnatstudio`) or Start Menu -* :menu:`Create new project` - - - Select :menu:`Simple Ada Project` and click :menu:`Next` - - Fill in a location to to deploy the project - - Set **main name** to *say_hello* and click :menu:`Apply` - -* Expand the **src** level in the Project View and double-click :filename:`say_hello.adb` - - - Replace the code in the file with the program shown on the previous slide - -* Execute the program by selecting :menu:`Build` :math:`\rightarrow` :menu:`Project` :math:`\rightarrow` :menu:`Build & Run` :math:`\rightarrow` :menu:`say_hello.adb` - - - Shortcut is the :math:`\blacktriangleright` in the icons bar - -* Result should appear in the bottom pane labeled *Run: say_hello.exe* - --------------------------------------- -Note on GNAT File Naming Conventions --------------------------------------- - -* GNAT compiler assumes one compilable entity per file - - * Package specification, subprogram body, etc - * So the body for :ada:`say_hello` should be the only thing in the file - -* Filenames should match the name of the compilable entity - - * Replacing "." with "-" - * File extension is ".ads" for specifications and ".adb" for bodies - * So the body for :ada:`say_hello` will be in :filename:`say_hello.adb` - - * If there was a specification for the subprogram, it would be in :filename:`say_hello.ads` - -* This is the **default** behavior. There are ways around both of these rules - - * For further information, see Section 3.3 *File Naming Topics and Utilities* in the **GNAT User's Guide** +********** +Overview +********** + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 010_overview/01-a_little_history.rst +.. include:: 010_overview/02-big_picture.rst +.. include:: 010_overview/03-setup.rst diff --git a/courses/fundamentals_of_ada/010_overview/01-a_little_history.rst b/courses/fundamentals_of_ada/010_overview/01-a_little_history.rst new file mode 100644 index 000000000..35aa997b1 --- /dev/null +++ b/courses/fundamentals_of_ada/010_overview/01-a_little_history.rst @@ -0,0 +1,65 @@ +================== +A Little History +================== + +---------- +The Name +---------- + +* First called DoD-1 +* Augusta Ada Byron, "first programmer" + + - Lord Byron's daughter + - Planned to calculate **Bernouilli's numbers** + - **First** computer program + - On **Babbage's Analytical Engine** + +* International Standards Organization standard + + - Updated about every 10 years + +* Writing **ADA** is like writing **CPLUSPLUS** + +-------------------------- +Ada Evolution Highlights +-------------------------- + +.. container:: columns + + .. container:: column + + .. container:: latex_environment footnotesize + + **Ada 83** + | Abstract Data Types + | Modules + | Concurrency + | Generics + | Exceptions + | + + **Ada 95** + | OOP + | Child Packages + | Annexes + | + + **Ada 2005** + | Multiple Inheritance + | Containers + | Ravenscar + + .. container:: column + + .. container:: latex_environment footnotesize + + **Ada 2012** + | Contracts + | Iterators + | Flexible Expressions + | + + **Ada 2022** + | :ada:`'Image` for all types + | Declare expression + diff --git a/courses/fundamentals_of_ada/010_overview/02-big_picture.rst b/courses/fundamentals_of_ada/010_overview/02-big_picture.rst new file mode 100644 index 000000000..b64fdb92a --- /dev/null +++ b/courses/fundamentals_of_ada/010_overview/02-big_picture.rst @@ -0,0 +1,317 @@ +============= +Big Picture +============= + +--------------------------------------- +Language Structure (Ada95 and Onward) +--------------------------------------- + +* **Required** :dfn:`Core` implementation + + - Reference Manual (RM) sections 1 :math:`\rightarrow` 13 + - Predefined Language Environment (Annex A) + - Interface to Other Languages (Annex B) + - Obsolescent Features (Annex J) + +* Optional :dfn:`Specialized Needs Annexes` + + - No additional syntax + - Systems Programming (C) + - Real-Time Systems (D) + - Distributed Systems (E) + - Information Systems (F) + - Numerics (G) + - High-Integrity Systems (H) + +------------------------- +*Core* Language Content +------------------------- + +* Ada is a **compiled**, **multi-paradigm** language +* With a **static** and **strong** type model + +.. container:: columns + + .. container:: column + + * Language-defined types, including string + * User-defined types + * Overloading procedures and functions + * Compile-time visibility control + * Abstract Data Types (ADT) + + .. container:: column + + * Exceptions + * Generic units + * Dynamic memory management + * Low-level programming + * Object-Oriented Programming (OOP) + * Concurrent programming + * Contract-Based Programming + +-------------------------- +The Type Model Saves Money +-------------------------- + +* Shifts fixes and costs to **early phases** + + +* Cost of an error *during a flight*? + +.. image:: relative_cost_to_fix_bugs.jpg + :height: 50% + +------------- +Subprograms +------------- + +- Syntax differs between *values* and *actions* +- :ada:`function` for a *value* + +.. code:: Ada + + function Is_Leaf (T : Tree) return Boolean + +- :ada:`procedure` for an *action* + +.. code:: Ada + + procedure Split (T : in out Tree; + Left : out Tree; + Right : out Tree) + +* Specification :math:`\neq` Implementation + + .. code:: Ada + + function Is_Leaf (T : Tree) return Boolean; + function Is_Leaf (T : Tree) return Boolean is + begin + ... + end Is_Leaf; + +--------------------------- +Dynamic Memory Management +--------------------------- + +* Raw pointers are error-prone +* Ada **access types** abstract facility + + - Static memory + - Allocated objects + - Subprograms + +* Accesses are **checked** + + - Unless unchecked mode is used + +* Supports user-defined storage managers + + - Storage **pools** + +---------- +Packages +---------- + +* Grouping of related entities + + - Subsystems like *Fire Control* and *Navigation* + - Common processing like *HMI* and *Operating System* + +* Separation of concerns + + - Specification :math:`\neq` Implementation + - Single definition by **designer** + - Multiple use by **users** + +* Information hiding + + - Compiler-enforced **visibility** + - Powerful **privacy** system + +------------ +Exceptions +------------ + +* Dealing with **errors**, **unexpected** events +* Separate error-handling code from logic +* Some flexibility + + - Re-raising + - Custom messages + +--------------- +Generic Units +--------------- + +.. container:: columns + + .. container:: column + + * Code Templates + + - Subprograms + - Packages + + * Parameterization + + - Strongly typed + - **Expressive** syntax + + .. container:: column + + .. image:: generic_template_to_instances.png + +----------------------------- +Object-Oriented Programming +----------------------------- + +* Inheritance +* Run-time polymorphism +* Dynamic **dispatching** +* Abstract types and subprograms +* **Interface** for multiple inheritance + +---------------------------- +Contract-Based Programming +---------------------------- + +* Pre- and post-conditions +* Formalizes specifications + + .. code:: Ada + + procedure Pop (S : in out Stack) with + Pre => not S.Empty, -- Requirement + Post => not S.Full; -- Guarantee + +* Type invariants + + .. code:: Ada + + type Table is private with Invariant => Sorted (Table); -- Guarantee + +-------------------------- +Language-Based Concurrency +-------------------------- + +* **Expressive** + + - Close to problem-space + - Specialized constructs + - **Explicit** interactions + +* **Run-time** handling + + - Maps to OS primitives + - Several support levels (Ravenscar...) + +* **Portable** + + - Source code + - People + - OS & Vendors + +----------------------- +Low Level Programming +----------------------- + +* **Representation** clauses +* Bit-level layouts +* Storage pools definition + + - With access safeties + +* Foreign language integration + + - C + - C++ + - Assembly + - etc... + +* Explicit specifications + + - Expressive + - Efficient + - Reasonably portable + - Abstractions preserved + +--------------------------------- +Standard Language Environment +--------------------------------- + +Standardized common API + +.. container:: columns + + .. container:: column + + * Types + + - Integer + - Floating-point + - Fixed-point + - Boolean + - Characters, Strings, Unicode + - etc... + + * Math + + - Trigonometric + - Complexes + + * Pseudo-random number generators + + .. container:: column + + * I/O + + - Text + - Binary (direct / sequential) + - Files + - Streams + + * Exceptions + + - Call-stack + + * **Command-line** arguments + * **Environment** variables + * **Containers** + + - Vector + - Map + +------------------------------ +Language Examination Summary +------------------------------ + +* Unique capabilities +* Three main goals + + - **Reliability**, maintainability + - Programming as a **human** activity + - Efficiency + +* Easy-to-use + + - ...and hard to misuse + - Very **few pitfalls** and exceptions + +----------------------------------- +So Why Isn't Ada Used Everywhere? +----------------------------------- + +.. container:: columns + + .. container:: column + + * "... in all matters of opinion our adversaries are insane" + + - *Mark Twain* + + .. container:: column + + .. image:: mark_twain.jpeg + diff --git a/courses/fundamentals_of_ada/010_overview/03-setup.rst b/courses/fundamentals_of_ada/010_overview/03-setup.rst new file mode 100644 index 000000000..9fa51109e --- /dev/null +++ b/courses/fundamentals_of_ada/010_overview/03-setup.rst @@ -0,0 +1,84 @@ +======= +Setup +======= + +------------------------- +Canonical First Program +------------------------- + +.. code:: Ada + + 1 with Ada.Text_IO; + 2 -- Everyone's first program + 3 procedure Say_Hello is + 4 begin + 5 Ada.Text_IO.Put_Line ("Hello, World!"); + 6 end Say_Hello; + +* Line 1 - :ada:`with` - Package dependency +* Line 2 - :ada:`--` - Comment +* Line 3 - :ada:`Say_Hello` - Subprogram name +* Line 4 - :ada:`begin` - Begin executable code +* Line 5 - :ada:`Ada.Text_IO.Put_Line ()` - Subprogram call +* (cont) - :ada:`"Hello, World!"` - String literal (type-checked) + +---------------------------------- +"Hello World" Lab - Command Line +---------------------------------- + +* Use an editor to enter the program shown on the previous slide + + - Use your favorite editor or just gedit/notepad/etc. + +* Save and name the file :filename:`say_hello.adb` exactly + + - In a command prompt shell, go to where the new file is located and issue the following command: + + + :command:`gprbuild say_hello` + +* In the same shell, invoke the resulting executable: + + - :command:`say_hello` (Windows) + - :command:`./say_hello` (Linux/Unix) + +--------------------------------------------- +"Hello World" Lab - :toolname:`GNAT Studio` +--------------------------------------------- + +* Start :toolname:`GNAT Studio` from the command-line (:command:`gnatstudio`) or Start Menu +* :menu:`Create new project` + + - Select :menu:`Simple Ada Project` and click :menu:`Next` + - Fill in a location to to deploy the project + - Set **main name** to *say_hello* and click :menu:`Apply` + +* Expand the **src** level in the Project View and double-click :filename:`say_hello.adb` + + - Replace the code in the file with the program shown on the previous slide + +* Execute the program by selecting :menu:`Build` :math:`\rightarrow` :menu:`Project` :math:`\rightarrow` :menu:`Build & Run` :math:`\rightarrow` :menu:`say_hello.adb` + + - Shortcut is the :math:`\blacktriangleright` in the icons bar + +* Result should appear in the bottom pane labeled *Run: say_hello.exe* + +-------------------------------------- +Note on GNAT File Naming Conventions +-------------------------------------- + +* GNAT compiler assumes one compilable entity per file + + * Package specification, subprogram body, etc + * So the body for :ada:`say_hello` should be the only thing in the file + +* Filenames should match the name of the compilable entity + + * Replacing "." with "-" + * File extension is ".ads" for specifications and ".adb" for bodies + * So the body for :ada:`say_hello` will be in :filename:`say_hello.adb` + + * If there was a specification for the subprogram, it would be in :filename:`say_hello.ads` + +* This is the **default** behavior. There are ways around both of these rules + + * For further information, see Section 3.3 *File Naming Topics and Utilities* in the **GNAT User's Guide** From 1b0f2d0b59331850822c940e003a63c4dd404c12 Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Mon, 9 Dec 2024 21:13:27 +0000 Subject: [PATCH 05/11] Resolve "Break 273_subprogram_contracts into chapters" --- .../273_subprogram_contracts.rst | 949 +----------------- .../01-introduction.rst | 134 +++ .../02-preconditions_and_postconditions.rst | 250 +++++ .../03-special_attributes.rst | 173 ++++ .../04-in_practice.rst | 256 +++++ .../273_subprogram_contracts/99-summary.rst | 55 + ...b.rst => 273_subprogram_contracts.lab.rst} | 10 +- ...racts.txt => 273_subprogram_contracts.txt} | 0 .../default.gpr | 0 .../main.adb | 0 .../priority_queue.adb | 0 .../priority_queue.ads | 0 12 files changed, 916 insertions(+), 911 deletions(-) create mode 100644 courses/fundamentals_of_ada/273_subprogram_contracts/01-introduction.rst create mode 100644 courses/fundamentals_of_ada/273_subprogram_contracts/02-preconditions_and_postconditions.rst create mode 100644 courses/fundamentals_of_ada/273_subprogram_contracts/03-special_attributes.rst create mode 100644 courses/fundamentals_of_ada/273_subprogram_contracts/04-in_practice.rst create mode 100644 courses/fundamentals_of_ada/273_subprogram_contracts/99-summary.rst rename courses/fundamentals_of_ada/labs/{adv_270_subprogram_contracts.lab.rst => 273_subprogram_contracts.lab.rst} (73%) rename courses/fundamentals_of_ada/labs/answers/{adv_270_subprogram_contracts.txt => 273_subprogram_contracts.txt} (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_270_subprogram_contracts => 273_subprogram_contracts}/default.gpr (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_270_subprogram_contracts => 273_subprogram_contracts}/main.adb (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_270_subprogram_contracts => 273_subprogram_contracts}/priority_queue.adb (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_270_subprogram_contracts => 273_subprogram_contracts}/priority_queue.ads (100%) diff --git a/courses/fundamentals_of_ada/273_subprogram_contracts.rst b/courses/fundamentals_of_ada/273_subprogram_contracts.rst index e42084a36..4e95d5e3b 100644 --- a/courses/fundamentals_of_ada/273_subprogram_contracts.rst +++ b/courses/fundamentals_of_ada/273_subprogram_contracts.rst @@ -1,908 +1,41 @@ -********************** -Subprogram Contracts -********************** - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - --------------------------- -:dfn:`Design-By-Contract` --------------------------- - -* Source code acting in roles of **client** and **supplier** under a binding **contract** - - - :dfn:`Contract` specifies *requirements* or *guarantees* - - - *"A specification of a software element that affects its use by potential clients."* (Bertrand Meyer) - - - :dfn:`Supplier` provides services - - - Guarantees specific functional behavior - - Has requirements for guarantees to hold - - - :dfn:`Client` utilizes services - - - Guarantees supplier's conditions are met - - Requires result to follow the subprogram's guarantees - ---------------- -Ada Contracts ---------------- - -* Ada contracts include enforcement - - - At compile-time: specific constructs, features, and rules - - At run-time: language-defined and user-defined exceptions - -* Facilities as part of the language definition - - - Range specifications - - Parameter modes - - Generic contracts - - OOP :ada:`interface` types - - Work well, but on a restricted set of use-cases - -* Contract aspects to be more expressive - - - Carried by subprograms - - ... or by types (seen later) - - Can have **arbitrary** conditions, more **versatile** - ------------------- -:dfn:`Assertion` ------------------- - -* Boolean expression expected to be :ada:`True` -* Said *to hold* when :ada:`True` -* Language-defined :ada:`pragma` - -.. code:: Ada - - pragma Assert (not Full (Stack)); - -- stack is not full - pragma Assert (Stack_Length = 0, - Message => "stack was not empty"); - -- stack is empty - -* Raises language-defined :ada:`Assertion_Error` exception if expression does not hold -* The :ada:`Ada.Assertions.Assert` subprogram wraps it - -.. code:: Ada - - package Ada.Assertions is - Assertion_Error : exception; - procedure Assert (Check : in Boolean); - procedure Assert (Check : in Boolean; Message : in String); - end Ada.Assertions; - ------- -Quiz ------- - -Which of the following statements is (are) correct? - - A. Contract principles apply only to newer versions of the language - B. :answer:`Contract should hold even for unique conditions and corner cases` - C. Contract principles were first implemented in Ada - D. You cannot be both supplier and client - -.. container:: animate - - Explanations - - A. No, but design-by-contract **aspects** were fully integrated into Ada 2012 - B. Yes, special case should be included in the contract - C. No, in eiffel, in 1986! - D. No, in fact you are always **both**, even the :ada:`Main` has a caller! - ------- -Quiz ------- - -Which of the following statements is (are) correct? - - A. :answer:`Assertions can be used in declarations` - B. Assertions can be used in expressions - C. :answer:`Any corrective action should happen before contract checks` - D. Assertions must be checked using :ada:`pragma Assert` - -.. container:: animate - - Explanations - - A. Will be checked at elaboration - B. No assertion expression, but :ada:`raise` expression exists - C. Exceptions as flow-control adds complexity, prefer a proactive :ada:`if` to a (reactive) :ada:`exception` handler - D. You can call :ada:`Ada.Assertions.Assert`, or even directly :ada:`raise Assertion_Error` - ------- -Quiz ------- - -Which of the following statements is (are) correct? - - A. :answer:`Defensive coding is a good practice` - B. Contracts can replace all defensive code - C. Contracts are executable constructs - D. Having exhaustive contracts will prevent run-time errors - -.. container:: animate - - Explanations - - A. Principles are sane, contracts extend those - B. See previous slide example - C. e.g. generic contracts are resolved at compile-time - D. A failing contract **will cause** a run-time error, only extensive (dynamic / static) analysis of contracted code may provide confidence in the absence of runtime errors (AoRTE) - -=================================== -Preconditions and Postconditions -=================================== - ------------------------------ -Subprogram-based Assertions ------------------------------ - -* **Explicit** part of a subprogram's **specification** - - - Unlike defensive code - -* :dfn:`Precondition` - - - Assertion expected to hold **prior to** subprogram call - -* :dfn:`Postcondition` - - - Assertion expected to hold **after** subprogram return - -* Requirements and guarantees on both supplier and client -* Syntax uses **aspects** - - .. code:: Ada - - procedure Push (This : in out Stack_T; - Value : Content_T) - with Pre => not Full (This), - Post => not Empty (This) - and Top (This) = Value; - ---------------------------------- -Requirements / Guarantees: Quiz ---------------------------------- - -* Given the following piece of code - - .. code:: Ada - - procedure Start is - begin - ... - Turn_On; - ... - - procedure Turn_On - with Pre => Has_Power, - Post => Is_On; - -* Complete the table in terms of requirements and guarantees - -.. list-table:: - - * - - - Client (:ada:`Start`) - - Supplier (:ada:`Turn_On`) - - * - Pre (:ada:`Has_Power`) - - :animate:`Requirement` - - :animate:`Guarantee` - - * - Post (:ada:`Is_On`) - - :animate:`Guarantee` - - :animate:`Requirement` - ------------------------ -Defensive Programming ------------------------ - -* Should be replaced by subprogram contracts when possible - -.. code:: Ada - - procedure Push (S : Stack) is - Entry_Length : constant Positive := Length (S); - begin - pragma Assert (not Is_Full (S)); -- entry condition - [...] - pragma Assert (Length (S) = Entry_Length + 1); -- exit condition - end Push; - -* Subprogram contracts are an **assertion** mechanism - - - **Not** a drop-in replacement for all defensive code - -.. code:: Ada - - procedure Force_Acquire (P : Peripheral) is - begin - if not Available (P) then - -- Corrective action - Force_Release (P); - pragma Assert (Available (P)); - end if; - - Acquire (P); - end; - ------------------------------ -Pre/Postcondition Semantics ------------------------------ - -* Calls inserted automatically by compiler - -| - -.. image:: pre_and_post_insertion_flow.svg - :width: 90% - -------------------------------------- -Contract with Quantified Expression -------------------------------------- - -* Pre- and post-conditions can be **arbitrary** :ada:`Boolean` expressions - -.. code:: Ada - - type Status_Flag is (Power, Locked, Running); - - procedure Clear_All_Status ( - Unit : in out Controller) - -- guarantees no flags remain set after call - with Post => (for all Flag in Status_Flag => - not Status_Indicated (Unit, Flag)); - - function Status_Indicated ( - Unit : Controller; - Flag : Status_Flag) - return Boolean; - -------------------------------------- -Visibility for Subprogram Contracts -------------------------------------- - -* **Any** visible name - - - All of the subprogram's **parameters** - - Can refer to functions **not yet specified** - - - Must be declared in same scope - - Different elaboration rules for expression functions - - .. code:: Ada - - function Top (This : Stack) return Content - with Pre => not Empty (This); - function Empty (This : Stack) return Boolean; - -* :ada:`Post` has access to special attributes - - - See later - ------------------------------------------- -Preconditions and Postconditions Example ------------------------------------------- - -* Multiple aspects separated by commas - -.. code:: Ada - - procedure Push (This : in out Stack; - Value : Content) - with Pre => not Full (This), - Post => not Empty (This) and Top (This) = Value; - ------------------------------------- -(Sub)Types Allow Simpler Contracts ------------------------------------- - -* Pre-condition - - .. code:: Ada - - procedure Compute_Square_Root (Input : Integer; - Result : out Natural) - with Pre => Input >= 0, - Post => (Result * Result) <= Input and - (Result + 1) * (Result + 1) > Input; - -* Subtype - - .. code:: Ada - - procedure Compute_Square_Root (Input : Natural; - Result : out Natural) - with - -- "Pre => Input >= 0" not needed - -- (Input can't be < 0) - Post => (Result * Result) <= Input and - (Result + 1) * (Result + 1) > Input; - ------- -Quiz ------- - -.. code:: Ada - - -- Convert string to Integer - function From_String ( S : String ) return Integer - with Pre => S'Length > 0; - - procedure Do_Something is - I : Integer := From_String (""); - begin - Put_Line (I'Image); - end Do_Something; - -Assuming :ada:`From_String` is defined somewhere, what happens -when :ada:`Do_Something` is run? - - A. "0" is printed - B. Constraint Error exception - C. :answer:`Assertion Error exception` - D. Undefined behavior - -.. container:: animate - - Explanations - - The call to :ada:`From_String` will fail its precondition, which is considered - an :ada:`Assertion_Error` exception. - ------- -Quiz ------- - -.. code:: Ada - - function Area (L : Positive; H : Positive) return Positive is - (L * H) - with Pre => ? - -Which pre-condition is necessary for :ada:`Area` to calculate the correct result for -all values :ada:`L` and :ada:`H` - - A. ``L > 0 and H > 0`` - B. ``L < Positive'Last and H < Positive'Last`` - C. ``L * H in Positive`` - D. :answer:`None of the above` - -.. container:: animate - - Explanations - - A. Parameters are :ada:`Positive`, so this is unnecessary - B. :ada:`L = Positive'Last-1 and H = Positive'Last-1` will still cause an overflow - C. Classic trap: the check itself may cause an overflow! - - Preventing an overflow requires using the expression :ada:`Integer'Last / L <= H` - -==================== -Special Attributes -==================== - --------------------------------------------- -Evaluate an Expression on Subprogram Entry --------------------------------------------- - -* Post-conditions may require knowledge of a subprogram's **entry context** - - .. code:: Ada - - procedure Increment (This : in out Integer) - with Post => ??? -- how to assert incrementation of `This`? - -* Language-defined attribute :ada:`'Old` -* Expression is **evaluated** at subprogram entry - - - After pre-conditions check - - Makes a copy - - + :ada:`limited` types are forbidden - + May be expensive - - - Expression can be **arbitrary** - - + Typically :ada:`in out` parameters and globals - - .. code:: Ada - - procedure Increment (This : in out Integer) with - Pre => This < Integer'Last, - Post => This = This'Old + 1; - ------------------------------------ -Example for Attribute :ada:`'Old` ------------------------------------ - - .. code:: Ada - - Global : String := Init_Global; - ... - -- In Global, move character at Index to the left one position, - -- and then increment the Index - procedure Shift_And_Advance (Index : in out Integer) is - begin - Global (Index) := Global (Index + 1); - Index := Index + 1; - end Shift_And_Advance; - -* Note the different uses of `'Old` in the postcondition - - .. code:: Ada - - procedure Shift_And_Advance (Index : in out Integer) with Post => - -- Global (Index) before call (so Global and Index are original) - Global (Index)'Old - -- Original Global and Original Index - = Global'Old (Index'Old) - and - -- Global after call and Index befor call - Global (Index'Old) - -- Global and Index after call - = Global (Index); - ------------------------------------------------- -Error on Conditional Evaluation of :ada:`'Old` ------------------------------------------------- - -* This code is **incorrect** - -.. code:: Ada - - procedure Clear_Character (In_String : in out String; - At_Position : Positive) - with Post => (if At_Position in In_String'Range - then In_String (At_Position)'Old = ' '); - -* Copies :ada:`In_String (At_Position)` on entry - - - Will raise an exception on entry if :ada:`At_Position not in In_String'Range` - - The postcondition's :ada:`if` check is not sufficient - -* Solution requires a full copy of :ada:`In_String` - -.. code:: Ada - - procedure Clear_Character (In_String : in out String; - At_Position : Positive) - with Post => (if At_Position in In_String'Range - then In_String'Old (At_Position) = ' '); - -------------------------------------------- -Postcondition Usage of Function Results -------------------------------------------- - -* :ada:`function` result can be read with :ada:`'Result` - -.. code:: Ada - - function Greatest_Common_Denominator (A, B : Positive) - return Positive with - Post => Is_GCD (A, B, - Greatest_Common_Denominator'Result); - ------- -Quiz ------- - -.. code:: Ada - - Database : String (1 .. 10) := "ABCDEFGHIJ"; - -- Set the value for the element at position Index in - -- array Database to Value and then increment Index by 1 - function Set_And_Move (Value : Character; - Index : in out Index_T) - return Boolean - with Post => ... - -Given the following expressions, what is their value if they are evaluated in the postcondition -of the call :ada:`Set_And_Move ('X', 4)`? - -.. container:: animate 2- - - .. image:: subprogram_contracts_special_attributes-legend.svg - :width: 60% - -.. container:: animate 1- - - * ``Database'Old (Index)`` - -.. container:: animate 2- - - .. image:: subprogram_contracts_special_attributes-answer1.svg - :width: 60% - -.. container:: animate 1- - - * ``Database (Index'Old)`` - -.. container:: animate 3- - - .. image:: subprogram_contracts_special_attributes-answer2.svg - :width: 60% - -.. container:: animate 1- - - * ``Database (Index)'Old`` - -.. container:: animate 4- - - .. image:: subprogram_contracts_special_attributes-answer3.svg - :width: 60% - -------------------------------------- -Stack Example (Spec with Contracts) -------------------------------------- - -.. container:: columns - - .. container:: column - - .. container:: latex_environment tiny - - .. include:: examples/adv_270_subprogram_contracts/special_attributes_spec.rst - - .. container:: column - - .. container:: latex_environment tiny - - .. include:: examples/adv_270_subprogram_contracts/special_attributes_body.rst - -============= -In Practice -============= - ----------------------------------------- -Pre/Postconditions: to Be or Not to Be ----------------------------------------- - -* **Preconditions** are reasonable **default** for run-time checks -* **Postconditions** advantages can be **comparatively** low - - - Use of :ada:`'Old` and :ada:`'Result` with (maybe deep) copy - - Very useful in **static analysis** contexts (Hoare triplets) - -* For **trusted** library, enabling **preconditions only** makes sense - - - Catch **user's errors** - - Library is trusted, so :ada:`Post => True` is a reasonable expectation - -* Typically contracts are used for **validation** -* Enabling subprogram contracts in production may be a valid trade-off depending on... - - - Exception failure **trace availability** in production - - Overall **timing constraints** of the final application - - Consequences of violations **propagation** - - Time and space **cost** of the contracts - -* Typically production settings favor telemetry and off-line analysis - -------------------------------------- -No Secret Precondition Requirements -------------------------------------- - -* Client should be able to **guarantee** them -* Enforced by the compiler - -.. code:: Ada - - package P is - function Foo return Bar - with Pre => Hidden; -- illegal private reference - private - function Hidden return Boolean; - end P; - ---------------------------------------- -Postconditions Are Good Documentation ---------------------------------------- - -.. code:: Ada - - procedure Reset - (Unit : in out DMA_Controller; - Stream : DMA_Stream_Selector) - with Post => - not Enabled (Unit, Stream) and - Operating_Mode (Unit, Stream) = Normal_Mode and - Selected_Channel (Unit, Stream) = Channel_0 and - not Double_Buffered (Unit, Stream) and - Priority (Unit, Stream) = Priority_Low and - (for all Interrupt in DMA_Interrupt => - not Interrupt_Enabled (Unit, Stream, Interrupt)); - --------------------------------------- -Postcondition Compared to Their Body --------------------------------------- - -* Specifying relevant properties may "repeat" the body - - - Unlike preconditions - - Typically **simpler** than the body - - Closer to a **re-phrasing** than a tautology - -* Good fit for *hard to solve and easy to check* problems - - - Solvers: :ada:`Solve (Find_Root'Result, Equation) = 0` - - Search: :ada:`Can_Exit (Path_To_Exit'Result, Maze)` - - Cryptography: :ada:`Match (Signer (Sign_Certificate'Result), Key.Public_Part)` - -* Bad fit for poorly-defined or self-defining subprograms - -.. code:: Ada - - function Get_Magic_Number return Integer - with Post => Get_Magic_Number'Result = 42 - -- Useless post-condition, simply repeating the body - is (42); - ------------------------------------------------ -Postcondition Compared to Their Body: Example ------------------------------------------------ - -.. code:: Ada - - function Greatest_Common_Denominator (A, B : Natural) - return Integer with - Post => Is_GCD (A, - B, - Greatest_Common_Denominator'Result); - - function Is_GCD (A, B, Candidate : Integer) - return Boolean is - (A rem Candidate = 0 and - B rem Candidate = 0 and - (for all K in 1 .. Integer'Min (A,B) => - (if (A rem K = 0 and B rem K = 0) - then K <= Candidate))); - ----------------------- -Contracts Code Reuse ----------------------- - -* Contracts are about **usage** and **behaviour** - - - Not optimization - - Not implementation details - - **Abstraction** level is typically high - -* Extracting them to :ada:`function` is a good idea - - - *Code as documentation, executable specification* - - Completes the **interface** that the client has access to - - Allows for **code reuse** - - .. code:: Ada - - procedure Withdraw (This : in out Account; - Amount : Currency) with - Pre => Open (This) and then Funds_Available (This, Amount), - Post => Balance (This) = Balance (This)'Old - Amount; - ... - function Funds_Available (This : Account; - Amount : Currency) - return Boolean is - (Amount > 0.0 and then Balance (This) >= Amount) - with Pre => Open (This); - -* A :ada:`function` may be unavoidable - - - Referencing private type components - ---------------------------------------- -Subprogram Contracts on Private Types ---------------------------------------- - -.. code:: Ada - - package P is - type T is private; - procedure Q (This : T) with - Pre => This.Total > 0; -- not legal - ... - function Current_Total (This : T) return Integer; - ... - procedure R (This : T) with - Pre => Current_Total (This) > 0; -- legal - ... - private - type T is record - Total : Natural ; - ... - end record; - function Current_Total (This : T) return Integer is - (This.Total); - end P; - ------------------------------------ -Preconditions or Explicit Checks? ------------------------------------ - -* Any requirement from the spec should be a pre-condition - - - If clients need to know the body, abstraction is **broken** - -* With pre-conditions - - .. code:: Ada - - type Stack (Capacity : Positive) is tagged private; - procedure Push (This : in out Stack; - Value : Content) with - Pre => not Full (This); - -* With defensive code, comments, and return values - - .. code:: Ada - - -- returns True iff push is successful - function Try_Push (This : in out Stack; - Value : Content) return Boolean - begin - if Full (This) then - return False; - end if; - ... - -* But not both - - - For the implementation, preconditions are a **guarantee** - - A subprogram body should **never** test them - ------------------------------ -Raising Specific Exceptions ------------------------------ - -* In the Exceptions module, we show how user-defined exceptions are better than pre-defined - - * Stack :ada:`Push` raising :ada:`Overflow_Error` rather than :ada:`Constraint_Error` - -* *Default* behavior for a preconditon failure is :ada:`Assertion_Error` - - * But it doesn't have to be! - -* Use *raise expression* in a precondition to get a different exception - - .. code:: Ada - - procedure Push (This : in out Stack; - Value : Content) with - Pre => not Full (This) or else Overflow_Error; - -* *Note: Postcondition failure only ever makes sense as an Assertion_Error* - - * It's the supplier's fault, not the client's - ------------------- -Assertion Policy ------------------- - -* Pre/postconditions can be controlled with :ada:`pragma Assertion_Policy` - - .. code:: Ada - - pragma Assertion_Policy - (Pre => Check, - Post => Ignore); - -* Fine **granularity** over assertion kinds and policy identifiers - - :url:`https://docs.adacore.com/gnat_rm-docs/html/gnat_rm/gnat_rm/implementation_defined_pragmas.html#pragma-assertion-policy` - - -* Certain advantage over explicit checks which are **harder** to disable - - - Conditional compilation via global :ada:`constant Boolean` - - .. code:: Ada - - procedure Push (This : in out Stack; Value : Content) is - begin - if Debugging then - if Full (This) then - raise Overflow; - end if; - end if; - -======== -Lab -======== - -.. include:: labs/adv_270_subprogram_contracts.lab.rst - -========= -Summary -========= - -------------------------------------- -Contract-Based Programming Benefits -------------------------------------- - -* Facilitates building software with reliability built-in - - - Software cannot work well unless "well" is carefully defined - - Clarifies design by defining obligations/benefits - -* Enhances readability and understandability - - - Specification contains explicitly expressed properties of code - -* Improves testability but also likelihood of passing! -* Aids in debugging -* Facilitates tool-based analysis - - - Compiler checks conformance to obligations - - Static analyzers (e.g., SPARK, GNAT Static Analysis Suite) can verify explicit precondition and postconditions - ---------- -Summary ---------- - -* Based on viewing source code as clients and suppliers with enforced obligations and guarantees -* No run-time penalties unless enforced -* OOP introduces the tricky issues - - - Inheritance of preconditions and postconditions, for example - -* Note that pre/postconditions can be used on concurrency constructs too - - .. list-table:: - :header-rows: 1 - :stub-columns: 1 - :width: 90% - - * - - - - Clients - - Suppliers - - * - Preconditions - - - Obligation - - Guarantee - - * - Postconditions - - - Guarantee - - Obligation +********************** +Subprogram Contracts +********************** + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 273_subprogram_contracts/01-introduction.rst +.. include:: 273_subprogram_contracts/02-preconditions_and_postconditions.rst +.. include:: 273_subprogram_contracts/03-special_attributes.rst +.. include:: 273_subprogram_contracts/04-in_practice.rst +.. include:: labs/273_subprogram_contracts.lab.rst +.. include:: 273_subprogram_contracts/99-summary.rst diff --git a/courses/fundamentals_of_ada/273_subprogram_contracts/01-introduction.rst b/courses/fundamentals_of_ada/273_subprogram_contracts/01-introduction.rst new file mode 100644 index 000000000..0e56dd6cf --- /dev/null +++ b/courses/fundamentals_of_ada/273_subprogram_contracts/01-introduction.rst @@ -0,0 +1,134 @@ +============== +Introduction +============== + +-------------------------- +:dfn:`Design-By-Contract` +-------------------------- + +* Source code acting in roles of **client** and **supplier** under a binding **contract** + + - :dfn:`Contract` specifies *requirements* or *guarantees* + + - *"A specification of a software element that affects its use by potential clients."* (Bertrand Meyer) + + - :dfn:`Supplier` provides services + + - Guarantees specific functional behavior + - Has requirements for guarantees to hold + + - :dfn:`Client` utilizes services + + - Guarantees supplier's conditions are met + - Requires result to follow the subprogram's guarantees + +--------------- +Ada Contracts +--------------- + +* Ada contracts include enforcement + + - At compile-time: specific constructs, features, and rules + - At run-time: language-defined and user-defined exceptions + +* Facilities as part of the language definition + + - Range specifications + - Parameter modes + - Generic contracts + - OOP :ada:`interface` types + - Work well, but on a restricted set of use-cases + +* Contract aspects to be more expressive + + - Carried by subprograms + - ... or by types (seen later) + - Can have **arbitrary** conditions, more **versatile** + +------------------ +:dfn:`Assertion` +------------------ + +* Boolean expression expected to be :ada:`True` +* Said *to hold* when :ada:`True` +* Language-defined :ada:`pragma` + +.. code:: Ada + + pragma Assert (not Full (Stack)); + -- stack is not full + pragma Assert (Stack_Length = 0, + Message => "stack was not empty"); + -- stack is empty + +* Raises language-defined :ada:`Assertion_Error` exception if expression does not hold +* The :ada:`Ada.Assertions.Assert` subprogram wraps it + +.. code:: Ada + + package Ada.Assertions is + Assertion_Error : exception; + procedure Assert (Check : in Boolean); + procedure Assert (Check : in Boolean; Message : in String); + end Ada.Assertions; + +------ +Quiz +------ + +Which of the following statements is (are) correct? + + A. Contract principles apply only to newer versions of the language + B. :answer:`Contract should hold even for unique conditions and corner cases` + C. Contract principles were first implemented in Ada + D. You cannot be both supplier and client + +.. container:: animate + + Explanations + + A. No, but design-by-contract **aspects** were fully integrated into Ada 2012 + B. Yes, special case should be included in the contract + C. No, in eiffel, in 1986! + D. No, in fact you are always **both**, even the :ada:`Main` has a caller! + +------ +Quiz +------ + +Which of the following statements is (are) correct? + + A. :answer:`Assertions can be used in declarations` + B. Assertions can be used in expressions + C. :answer:`Any corrective action should happen before contract checks` + D. Assertions must be checked using :ada:`pragma Assert` + +.. container:: animate + + Explanations + + A. Will be checked at elaboration + B. No assertion expression, but :ada:`raise` expression exists + C. Exceptions as flow-control adds complexity, prefer a proactive :ada:`if` to a (reactive) :ada:`exception` handler + D. You can call :ada:`Ada.Assertions.Assert`, or even directly :ada:`raise Assertion_Error` + +------ +Quiz +------ + +Which of the following statements is (are) correct? + + A. :answer:`Defensive coding is a good practice` + B. Contracts can replace all defensive code + C. Contracts are executable constructs + D. Having exhaustive contracts will prevent run-time errors + +.. container:: animate + + Explanations + + A. Principles are sane, contracts extend those + B. See previous slide example + C. e.g. generic contracts are resolved at compile-time + D. A failing contract **will cause** a run-time error, only extensive (dynamic / static) analysis of contracted code may provide confidence in the absence of runtime errors (AoRTE) + diff --git a/courses/fundamentals_of_ada/273_subprogram_contracts/02-preconditions_and_postconditions.rst b/courses/fundamentals_of_ada/273_subprogram_contracts/02-preconditions_and_postconditions.rst new file mode 100644 index 000000000..f48efd358 --- /dev/null +++ b/courses/fundamentals_of_ada/273_subprogram_contracts/02-preconditions_and_postconditions.rst @@ -0,0 +1,250 @@ +=================================== +Preconditions and Postconditions +=================================== + +----------------------------- +Subprogram-based Assertions +----------------------------- + +* **Explicit** part of a subprogram's **specification** + + - Unlike defensive code + +* :dfn:`Precondition` + + - Assertion expected to hold **prior to** subprogram call + +* :dfn:`Postcondition` + + - Assertion expected to hold **after** subprogram return + +* Requirements and guarantees on both supplier and client +* Syntax uses **aspects** + + .. code:: Ada + + procedure Push (This : in out Stack_T; + Value : Content_T) + with Pre => not Full (This), + Post => not Empty (This) + and Top (This) = Value; + +--------------------------------- +Requirements / Guarantees: Quiz +--------------------------------- + +* Given the following piece of code + + .. code:: Ada + + procedure Start is + begin + ... + Turn_On; + ... + + procedure Turn_On + with Pre => Has_Power, + Post => Is_On; + +* Complete the table in terms of requirements and guarantees + +.. list-table:: + + * - + - Client (:ada:`Start`) + - Supplier (:ada:`Turn_On`) + + * - Pre (:ada:`Has_Power`) + - :animate:`Requirement` + - :animate:`Guarantee` + + * - Post (:ada:`Is_On`) + - :animate:`Guarantee` + - :animate:`Requirement` + +----------------------- +Defensive Programming +----------------------- + +* Should be replaced by subprogram contracts when possible + +.. code:: Ada + + procedure Push (S : Stack) is + Entry_Length : constant Positive := Length (S); + begin + pragma Assert (not Is_Full (S)); -- entry condition + [...] + pragma Assert (Length (S) = Entry_Length + 1); -- exit condition + end Push; + +* Subprogram contracts are an **assertion** mechanism + + - **Not** a drop-in replacement for all defensive code + +.. code:: Ada + + procedure Force_Acquire (P : Peripheral) is + begin + if not Available (P) then + -- Corrective action + Force_Release (P); + pragma Assert (Available (P)); + end if; + + Acquire (P); + end; + +----------------------------- +Pre/Postcondition Semantics +----------------------------- + +* Calls inserted automatically by compiler + +| + +.. image:: pre_and_post_insertion_flow.svg + :width: 90% + +------------------------------------- +Contract with Quantified Expression +------------------------------------- + +* Pre- and post-conditions can be **arbitrary** :ada:`Boolean` expressions + +.. code:: Ada + + type Status_Flag is (Power, Locked, Running); + + procedure Clear_All_Status ( + Unit : in out Controller) + -- guarantees no flags remain set after call + with Post => (for all Flag in Status_Flag => + not Status_Indicated (Unit, Flag)); + + function Status_Indicated ( + Unit : Controller; + Flag : Status_Flag) + return Boolean; + +------------------------------------- +Visibility for Subprogram Contracts +------------------------------------- + +* **Any** visible name + + - All of the subprogram's **parameters** + - Can refer to functions **not yet specified** + + - Must be declared in same scope + - Different elaboration rules for expression functions + + .. code:: Ada + + function Top (This : Stack) return Content + with Pre => not Empty (This); + function Empty (This : Stack) return Boolean; + +* :ada:`Post` has access to special attributes + + - See later + +------------------------------------------ +Preconditions and Postconditions Example +------------------------------------------ + +* Multiple aspects separated by commas + +.. code:: Ada + + procedure Push (This : in out Stack; + Value : Content) + with Pre => not Full (This), + Post => not Empty (This) and Top (This) = Value; + +------------------------------------ +(Sub)Types Allow Simpler Contracts +------------------------------------ + +* Pre-condition + + .. code:: Ada + + procedure Compute_Square_Root (Input : Integer; + Result : out Natural) + with Pre => Input >= 0, + Post => (Result * Result) <= Input and + (Result + 1) * (Result + 1) > Input; + +* Subtype + + .. code:: Ada + + procedure Compute_Square_Root (Input : Natural; + Result : out Natural) + with + -- "Pre => Input >= 0" not needed + -- (Input can't be < 0) + Post => (Result * Result) <= Input and + (Result + 1) * (Result + 1) > Input; + +------ +Quiz +------ + +.. code:: Ada + + -- Convert string to Integer + function From_String ( S : String ) return Integer + with Pre => S'Length > 0; + + procedure Do_Something is + I : Integer := From_String (""); + begin + Put_Line (I'Image); + end Do_Something; + +Assuming :ada:`From_String` is defined somewhere, what happens +when :ada:`Do_Something` is run? + + A. "0" is printed + B. Constraint Error exception + C. :answer:`Assertion Error exception` + D. Undefined behavior + +.. container:: animate + + Explanations + + The call to :ada:`From_String` will fail its precondition, which is considered + an :ada:`Assertion_Error` exception. + +------ +Quiz +------ + +.. code:: Ada + + function Area (L : Positive; H : Positive) return Positive is + (L * H) + with Pre => ? + +Which pre-condition is necessary for :ada:`Area` to calculate the correct result for +all values :ada:`L` and :ada:`H` + + A. ``L > 0 and H > 0`` + B. ``L < Positive'Last and H < Positive'Last`` + C. ``L * H in Positive`` + D. :answer:`None of the above` + +.. container:: animate + + Explanations + + A. Parameters are :ada:`Positive`, so this is unnecessary + B. :ada:`L = Positive'Last-1 and H = Positive'Last-1` will still cause an overflow + C. Classic trap: the check itself may cause an overflow! + + Preventing an overflow requires using the expression :ada:`Integer'Last / L <= H` + diff --git a/courses/fundamentals_of_ada/273_subprogram_contracts/03-special_attributes.rst b/courses/fundamentals_of_ada/273_subprogram_contracts/03-special_attributes.rst new file mode 100644 index 000000000..19f790bf1 --- /dev/null +++ b/courses/fundamentals_of_ada/273_subprogram_contracts/03-special_attributes.rst @@ -0,0 +1,173 @@ +==================== +Special Attributes +==================== + +-------------------------------------------- +Evaluate an Expression on Subprogram Entry +-------------------------------------------- + +* Post-conditions may require knowledge of a subprogram's **entry context** + + .. code:: Ada + + procedure Increment (This : in out Integer) + with Post => ??? -- how to assert incrementation of `This`? + +* Language-defined attribute :ada:`'Old` +* Expression is **evaluated** at subprogram entry + + - After pre-conditions check + - Makes a copy + + + :ada:`limited` types are forbidden + + May be expensive + + - Expression can be **arbitrary** + + + Typically :ada:`in out` parameters and globals + + .. code:: Ada + + procedure Increment (This : in out Integer) with + Pre => This < Integer'Last, + Post => This = This'Old + 1; + +----------------------------------- +Example for Attribute :ada:`'Old` +----------------------------------- + + .. code:: Ada + + Global : String := Init_Global; + ... + -- In Global, move character at Index to the left one position, + -- and then increment the Index + procedure Shift_And_Advance (Index : in out Integer) is + begin + Global (Index) := Global (Index + 1); + Index := Index + 1; + end Shift_And_Advance; + +* Note the different uses of `'Old` in the postcondition + + .. code:: Ada + + procedure Shift_And_Advance (Index : in out Integer) with Post => + -- Global (Index) before call (so Global and Index are original) + Global (Index)'Old + -- Original Global and Original Index + = Global'Old (Index'Old) + and + -- Global after call and Index befor call + Global (Index'Old) + -- Global and Index after call + = Global (Index); + +------------------------------------------------ +Error on Conditional Evaluation of :ada:`'Old` +------------------------------------------------ + +* This code is **incorrect** + +.. code:: Ada + + procedure Clear_Character (In_String : in out String; + At_Position : Positive) + with Post => (if At_Position in In_String'Range + then In_String (At_Position)'Old = ' '); + +* Copies :ada:`In_String (At_Position)` on entry + + - Will raise an exception on entry if :ada:`At_Position not in In_String'Range` + - The postcondition's :ada:`if` check is not sufficient + +* Solution requires a full copy of :ada:`In_String` + +.. code:: Ada + + procedure Clear_Character (In_String : in out String; + At_Position : Positive) + with Post => (if At_Position in In_String'Range + then In_String'Old (At_Position) = ' '); + +------------------------------------------- +Postcondition Usage of Function Results +------------------------------------------- + +* :ada:`function` result can be read with :ada:`'Result` + +.. code:: Ada + + function Greatest_Common_Denominator (A, B : Positive) + return Positive with + Post => Is_GCD (A, B, + Greatest_Common_Denominator'Result); + +------ +Quiz +------ + +.. code:: Ada + + Database : String (1 .. 10) := "ABCDEFGHIJ"; + -- Set the value for the element at position Index in + -- array Database to Value and then increment Index by 1 + function Set_And_Move (Value : Character; + Index : in out Index_T) + return Boolean + with Post => ... + +Given the following expressions, what is their value if they are evaluated in the postcondition +of the call :ada:`Set_And_Move ('X', 4)`? + +.. container:: animate 2- + + .. image:: subprogram_contracts_special_attributes-legend.svg + :width: 60% + +.. container:: animate 1- + + * ``Database'Old (Index)`` + +.. container:: animate 2- + + .. image:: subprogram_contracts_special_attributes-answer1.svg + :width: 60% + +.. container:: animate 1- + + * ``Database (Index'Old)`` + +.. container:: animate 3- + + .. image:: subprogram_contracts_special_attributes-answer2.svg + :width: 60% + +.. container:: animate 1- + + * ``Database (Index)'Old`` + +.. container:: animate 4- + + .. image:: subprogram_contracts_special_attributes-answer3.svg + :width: 60% + +------------------------------------- +Stack Example (Spec with Contracts) +------------------------------------- + +.. container:: columns + + .. container:: column + + .. container:: latex_environment tiny + + .. include:: ../examples/adv_270_subprogram_contracts/special_attributes_spec.rst + + .. container:: column + + .. container:: latex_environment tiny + + .. include:: ../examples/adv_270_subprogram_contracts/special_attributes_body.rst + + diff --git a/courses/fundamentals_of_ada/273_subprogram_contracts/04-in_practice.rst b/courses/fundamentals_of_ada/273_subprogram_contracts/04-in_practice.rst new file mode 100644 index 000000000..af6bbfa37 --- /dev/null +++ b/courses/fundamentals_of_ada/273_subprogram_contracts/04-in_practice.rst @@ -0,0 +1,256 @@ +============= +In Practice +============= + +---------------------------------------- +Pre/Postconditions: to Be or Not to Be +---------------------------------------- + +* **Preconditions** are reasonable **default** for run-time checks +* **Postconditions** advantages can be **comparatively** low + + - Use of :ada:`'Old` and :ada:`'Result` with (maybe deep) copy + - Very useful in **static analysis** contexts (Hoare triplets) + +* For **trusted** library, enabling **preconditions only** makes sense + + - Catch **user's errors** + - Library is trusted, so :ada:`Post => True` is a reasonable expectation + +* Typically contracts are used for **validation** +* Enabling subprogram contracts in production may be a valid trade-off depending on... + + - Exception failure **trace availability** in production + - Overall **timing constraints** of the final application + - Consequences of violations **propagation** + - Time and space **cost** of the contracts + +* Typically production settings favor telemetry and off-line analysis + +------------------------------------- +No Secret Precondition Requirements +------------------------------------- + +* Client should be able to **guarantee** them +* Enforced by the compiler + +.. code:: Ada + + package P is + function Foo return Bar + with Pre => Hidden; -- illegal private reference + private + function Hidden return Boolean; + end P; + +--------------------------------------- +Postconditions Are Good Documentation +--------------------------------------- + +.. code:: Ada + + procedure Reset + (Unit : in out DMA_Controller; + Stream : DMA_Stream_Selector) + with Post => + not Enabled (Unit, Stream) and + Operating_Mode (Unit, Stream) = Normal_Mode and + Selected_Channel (Unit, Stream) = Channel_0 and + not Double_Buffered (Unit, Stream) and + Priority (Unit, Stream) = Priority_Low and + (for all Interrupt in DMA_Interrupt => + not Interrupt_Enabled (Unit, Stream, Interrupt)); + +-------------------------------------- +Postcondition Compared to Their Body +-------------------------------------- + +* Specifying relevant properties may "repeat" the body + + - Unlike preconditions + - Typically **simpler** than the body + - Closer to a **re-phrasing** than a tautology + +* Good fit for *hard to solve and easy to check* problems + + - Solvers: :ada:`Solve (Find_Root'Result, Equation) = 0` + - Search: :ada:`Can_Exit (Path_To_Exit'Result, Maze)` + - Cryptography: :ada:`Match (Signer (Sign_Certificate'Result), Key.Public_Part)` + +* Bad fit for poorly-defined or self-defining subprograms + +.. code:: Ada + + function Get_Magic_Number return Integer + with Post => Get_Magic_Number'Result = 42 + -- Useless post-condition, simply repeating the body + is (42); + +----------------------------------------------- +Postcondition Compared to Their Body: Example +----------------------------------------------- + +.. code:: Ada + + function Greatest_Common_Denominator (A, B : Natural) + return Integer with + Post => Is_GCD (A, + B, + Greatest_Common_Denominator'Result); + + function Is_GCD (A, B, Candidate : Integer) + return Boolean is + (A rem Candidate = 0 and + B rem Candidate = 0 and + (for all K in 1 .. Integer'Min (A,B) => + (if (A rem K = 0 and B rem K = 0) + then K <= Candidate))); + +---------------------- +Contracts Code Reuse +---------------------- + +* Contracts are about **usage** and **behaviour** + + - Not optimization + - Not implementation details + - **Abstraction** level is typically high + +* Extracting them to :ada:`function` is a good idea + + - *Code as documentation, executable specification* + - Completes the **interface** that the client has access to + - Allows for **code reuse** + + .. code:: Ada + + procedure Withdraw (This : in out Account; + Amount : Currency) with + Pre => Open (This) and then Funds_Available (This, Amount), + Post => Balance (This) = Balance (This)'Old - Amount; + ... + function Funds_Available (This : Account; + Amount : Currency) + return Boolean is + (Amount > 0.0 and then Balance (This) >= Amount) + with Pre => Open (This); + +* A :ada:`function` may be unavoidable + + - Referencing private type components + +--------------------------------------- +Subprogram Contracts on Private Types +--------------------------------------- + +.. code:: Ada + + package P is + type T is private; + procedure Q (This : T) with + Pre => This.Total > 0; -- not legal + ... + function Current_Total (This : T) return Integer; + ... + procedure R (This : T) with + Pre => Current_Total (This) > 0; -- legal + ... + private + type T is record + Total : Natural ; + ... + end record; + function Current_Total (This : T) return Integer is + (This.Total); + end P; + +----------------------------------- +Preconditions or Explicit Checks? +----------------------------------- + +* Any requirement from the spec should be a pre-condition + + - If clients need to know the body, abstraction is **broken** + +* With pre-conditions + + .. code:: Ada + + type Stack (Capacity : Positive) is tagged private; + procedure Push (This : in out Stack; + Value : Content) with + Pre => not Full (This); + +* With defensive code, comments, and return values + + .. code:: Ada + + -- returns True iff push is successful + function Try_Push (This : in out Stack; + Value : Content) return Boolean + begin + if Full (This) then + return False; + end if; + ... + +* But not both + + - For the implementation, preconditions are a **guarantee** + - A subprogram body should **never** test them + +----------------------------- +Raising Specific Exceptions +----------------------------- + +* In the Exceptions module, we show how user-defined exceptions are better than pre-defined + + * Stack :ada:`Push` raising :ada:`Overflow_Error` rather than :ada:`Constraint_Error` + +* *Default* behavior for a preconditon failure is :ada:`Assertion_Error` + + * But it doesn't have to be! + +* Use *raise expression* in a precondition to get a different exception + + .. code:: Ada + + procedure Push (This : in out Stack; + Value : Content) with + Pre => not Full (This) or else Overflow_Error; + +* *Note: Postcondition failure only ever makes sense as an Assertion_Error* + + * It's the supplier's fault, not the client's + +------------------ +Assertion Policy +------------------ + +* Pre/postconditions can be controlled with :ada:`pragma Assertion_Policy` + + .. code:: Ada + + pragma Assertion_Policy + (Pre => Check, + Post => Ignore); + +* Fine **granularity** over assertion kinds and policy identifiers + + :url:`https://docs.adacore.com/gnat_rm-docs/html/gnat_rm/gnat_rm/implementation_defined_pragmas.html#pragma-assertion-policy` + + +* Certain advantage over explicit checks which are **harder** to disable + + - Conditional compilation via global :ada:`constant Boolean` + + .. code:: Ada + + procedure Push (This : in out Stack; Value : Content) is + begin + if Debugging then + if Full (This) then + raise Overflow; + end if; + end if; + diff --git a/courses/fundamentals_of_ada/273_subprogram_contracts/99-summary.rst b/courses/fundamentals_of_ada/273_subprogram_contracts/99-summary.rst new file mode 100644 index 000000000..ecede7354 --- /dev/null +++ b/courses/fundamentals_of_ada/273_subprogram_contracts/99-summary.rst @@ -0,0 +1,55 @@ +========= +Summary +========= + +------------------------------------- +Contract-Based Programming Benefits +------------------------------------- + +* Facilitates building software with reliability built-in + + - Software cannot work well unless "well" is carefully defined + - Clarifies design by defining obligations/benefits + +* Enhances readability and understandability + + - Specification contains explicitly expressed properties of code + +* Improves testability but also likelihood of passing! +* Aids in debugging +* Facilitates tool-based analysis + + - Compiler checks conformance to obligations + - Static analyzers (e.g., SPARK, GNAT Static Analysis Suite) can verify explicit precondition and postconditions + +--------- +Summary +--------- + +* Based on viewing source code as clients and suppliers with enforced obligations and guarantees +* No run-time penalties unless enforced +* OOP introduces the tricky issues + + - Inheritance of preconditions and postconditions, for example + +* Note that pre/postconditions can be used on concurrency constructs too + + .. list-table:: + :header-rows: 1 + :stub-columns: 1 + :width: 90% + + * - + + - Clients + - Suppliers + + * - Preconditions + + - Obligation + - Guarantee + + * - Postconditions + + - Guarantee + - Obligation diff --git a/courses/fundamentals_of_ada/labs/adv_270_subprogram_contracts.lab.rst b/courses/fundamentals_of_ada/labs/273_subprogram_contracts.lab.rst similarity index 73% rename from courses/fundamentals_of_ada/labs/adv_270_subprogram_contracts.lab.rst rename to courses/fundamentals_of_ada/labs/273_subprogram_contracts.lab.rst index 835417da4..0e8deb3c4 100644 --- a/courses/fundamentals_of_ada/labs/adv_270_subprogram_contracts.lab.rst +++ b/courses/fundamentals_of_ada/labs/273_subprogram_contracts.lab.rst @@ -1,3 +1,7 @@ +======== +Lab +======== + -------------------------- Subprogram Contracts Lab -------------------------- @@ -30,16 +34,16 @@ Subprogram Contracts Lab Subprogram Contracts Lab Solution - Queue (Spec) -------------------------------------------------- -.. container:: source_include labs/answers/adv_270_subprogram_contracts.txt :start-after:--Queue_Spec :end-before:--Queue_Spec :code:Ada :number-lines:1 +.. container:: source_include labs/answers/273_subprogram_contracts.txt :start-after:--Queue_Spec :end-before:--Queue_Spec :code:Ada :number-lines:1 -------------------------------------------------- Subprogram Contracts Lab Solution - Queue (Body) -------------------------------------------------- -.. container:: source_include labs/answers/adv_270_subprogram_contracts.txt :start-after:--Queue_Body :end-before:--Queue_Body :code:Ada :number-lines:1 +.. container:: source_include labs/answers/273_subprogram_contracts.txt :start-after:--Queue_Body :end-before:--Queue_Body :code:Ada :number-lines:1 ------------------------------------------- Subprograms Contracts Lab Solution - Main ------------------------------------------- -.. container:: source_include labs/answers/adv_270_subprogram_contracts.txt :start-after:--Main :end-before:--Main :code:Ada :number-lines:1 +.. container:: source_include labs/answers/273_subprogram_contracts.txt :start-after:--Main :end-before:--Main :code:Ada :number-lines:1 diff --git a/courses/fundamentals_of_ada/labs/answers/adv_270_subprogram_contracts.txt b/courses/fundamentals_of_ada/labs/answers/273_subprogram_contracts.txt similarity index 100% rename from courses/fundamentals_of_ada/labs/answers/adv_270_subprogram_contracts.txt rename to courses/fundamentals_of_ada/labs/answers/273_subprogram_contracts.txt diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/default.gpr b/courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/default.gpr similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/default.gpr rename to courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/default.gpr diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/main.adb b/courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/main.adb similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/main.adb rename to courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/main.adb diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/priority_queue.adb b/courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/priority_queue.adb similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/priority_queue.adb rename to courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/priority_queue.adb diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/priority_queue.ads b/courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/priority_queue.ads similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_270_subprogram_contracts/priority_queue.ads rename to courses/fundamentals_of_ada/labs/prompts/273_subprogram_contracts/priority_queue.ads From ec0bcf92090ba2ac37a1e77bf7d26a09c2b5a940 Mon Sep 17 00:00:00 2001 From: Dana Binkley Date: Tue, 10 Dec 2024 12:45:25 +0000 Subject: [PATCH 06/11] Slides/2 problems found from pat --- .../030_basic_types/07-real_types.rst | 4 ++-- .../04-assignment_statements.rst | 2 +- .../05-conditional_statements.rst | 2 +- .../03-unconstrained_array_types.rst | 4 ++-- .../05-when_to_use_or_avoid_private_types.rst | 2 +- .../labs/030_basic_types.lab.rst | 24 +++++++++---------- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/courses/fundamentals_of_ada/030_basic_types/07-real_types.rst b/courses/fundamentals_of_ada/030_basic_types/07-real_types.rst index 36dfe58dd..2d96a9c3c 100644 --- a/courses/fundamentals_of_ada/030_basic_types/07-real_types.rst +++ b/courses/fundamentals_of_ada/030_basic_types/07-real_types.rst @@ -167,9 +167,9 @@ What is the output of this code? Put_Line (Float'Image (F)); end; -A. 7.6 +A. 7.6E-01 B. Compile Error -C. 8.0 +C. 8.0E-01 D. :answer:`0.0` .. container:: animate diff --git a/courses/fundamentals_of_ada/040_statements/04-assignment_statements.rst b/courses/fundamentals_of_ada/040_statements/04-assignment_statements.rst index 136bc1ace..d779d9925 100644 --- a/courses/fundamentals_of_ada/040_statements/04-assignment_statements.rst +++ b/courses/fundamentals_of_ada/040_statements/04-assignment_statements.rst @@ -88,7 +88,7 @@ Aliasing the Assignment Target // becomes total += value; -* Ada 2022 implements this by using the target name symbol **@** +* Ada 2022 implements this by using the target name symbol :ada:`@` .. code:: Ada diff --git a/courses/fundamentals_of_ada/040_statements/05-conditional_statements.rst b/courses/fundamentals_of_ada/040_statements/05-conditional_statements.rst index 82e8c1166..3585ba49c 100644 --- a/courses/fundamentals_of_ada/040_statements/05-conditional_statements.rst +++ b/courses/fundamentals_of_ada/040_statements/05-conditional_statements.rst @@ -204,7 +204,7 @@ D. | ``end if;`` Explanations * :ada:`A` uses the C-style equality/inequality operators - * :ada:`D` is legal because :ada:`else` is not required + * :ada:`D` is legal because :ada:`else` is not required for an :ada:`if` block ------ Quiz diff --git a/courses/fundamentals_of_ada/050_array_types/03-unconstrained_array_types.rst b/courses/fundamentals_of_ada/050_array_types/03-unconstrained_array_types.rst index b43e2d1a1..a30422ca1 100644 --- a/courses/fundamentals_of_ada/050_array_types/03-unconstrained_array_types.rst +++ b/courses/fundamentals_of_ada/050_array_types/03-unconstrained_array_types.rst @@ -57,8 +57,8 @@ Supplying Index Constraints for Objects .. code:: Ada - Weekdays(Sat) := 0.0; -- Compiler error - Weekend(Mon) := 0.0; -- Compiler error + Weekdays(Sat) := 0.0; -- Constraint error + Weekend(Mon) := 0.0; -- Constraint error --------------------------------------- Bounds Must Satisfy Type Constraints diff --git a/courses/fundamentals_of_ada/110_private_types/05-when_to_use_or_avoid_private_types.rst b/courses/fundamentals_of_ada/110_private_types/05-when_to_use_or_avoid_private_types.rst index 00ad67c5a..4950d4185 100644 --- a/courses/fundamentals_of_ada/110_private_types/05-when_to_use_or_avoid_private_types.rst +++ b/courses/fundamentals_of_ada/110_private_types/05-when_to_use_or_avoid_private_types.rst @@ -46,5 +46,5 @@ When to Avoid Private Types type Vector is array (Positive range <>) of Float; V : Vector (1 .. 3); ... - V (1) := Alpha; + V (1) := Alpha; -- Illegal since Vector is private diff --git a/courses/fundamentals_of_ada/labs/030_basic_types.lab.rst b/courses/fundamentals_of_ada/labs/030_basic_types.lab.rst index 59374c515..6a05a614d 100644 --- a/courses/fundamentals_of_ada/labs/030_basic_types.lab.rst +++ b/courses/fundamentals_of_ada/labs/030_basic_types.lab.rst @@ -69,7 +69,18 @@ Basic Types Lab Hints .. code:: Ada 'Image (Object) - Object'Image + Object'Image + +-------------------------- +Basic Types Extra Credit +-------------------------- + +* See what happens when your data is invalid / illegal + + - Number of tests = 0 + - Assign a very large number to the test score total + - Color type only has one value + - Add a number larger than 360 to the circle value ---------------------------------------- Basic Types Lab Solution - Declarations @@ -83,14 +94,3 @@ Basic Types Lab Solution - Implementation .. container:: source_include labs/answers/030_basic_types.txt :start-after:--Implementation :end-before:--Implementation :code:Ada :number-lines:18 --------------------------- -Basic Types Extra Credit --------------------------- - -* See what happens when your data is invalid / illegal - - - Number of tests = 0 - - Assign a very large number to the test score total - - Color type only has one value - - Add a number larger than 360 to the circle value - From f5f05b24714a5b5dee8b47d35752524867eb274a Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Tue, 10 Dec 2024 15:19:09 +0000 Subject: [PATCH 07/11] Slides/add image overlay capability --- pandoc/beamer_filter.py | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/pandoc/beamer_filter.py b/pandoc/beamer_filter.py index 470c8d895..3c192bf15 100755 --- a/pandoc/beamer_filter.py +++ b/pandoc/beamer_filter.py @@ -362,6 +362,7 @@ def source_file_contents(filename, keywords): "source_include", "admonition", "animate", + "overlay", "speakernote", "columns", "column", @@ -468,6 +469,57 @@ def animate(classes, contents): return value +############## +## OVERLAYS ## +############## + +""" + We are going to use a container to actually overlay one + container with another. This will be most useful when + you want to overlay one image with another image to + show image animation. + The format of the directive is: + + .. container:: overlay + + Slide number is the "slide" to display the contents. + (Unlike "animate", whatever you overlay will get replaced + by the next overlay - it's not actual layers) + A number will appear on the specific overlay. + NOTE: We use "onlyenv" to make the block appear, so if the blocks (images) + are not the same size, there will probably be some resizing, makeing things + look bad. +""" + + +def is_overlay(classes): + return ("container" in classes) and ("overlay" in classes) + + +def overlay(classes, contents): + slide_number = 1 + dash = "-" + if len(classes) > 2: + requested = classes[2] + if len(requested) > 0: + slide_number = int(requested) + + slide_number = str(slide_number) + first = { + "t": "RawBlock", + "c": ["latex", "\\begin{onlyenv}<" + slide_number + ">"], + } + last = {"t": "RawBlock", "c": ["latex", "\\end{onlyenv}"]} + + value = [] + value.append(first) + for c in contents: + value.append(c) + value.append(last) + + return value + + ######################## ## LATEX ENVIRONMENTS ## ######################## @@ -834,6 +886,9 @@ def perform_filter(key, value, format, meta): if is_animate(classes): return animate(classes, contents) + if is_overlay(classes): + return overlay(classes, contents) + if is_latex_environment(classes): return latex_environment(classes, contents) From 57f094b9c703837fc9f3d41b7155da6154f0a2d7 Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Tue, 10 Dec 2024 15:19:23 +0000 Subject: [PATCH 08/11] Slides/add color capability to slides --- pandoc/beamer_filter.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/pandoc/beamer_filter.py b/pandoc/beamer_filter.py index 3c192bf15..a4c0dcc43 100755 --- a/pandoc/beamer_filter.py +++ b/pandoc/beamer_filter.py @@ -168,6 +168,20 @@ def latex_animate(text): return "\\onslide<2->{" + text + "}" +""" +latex_colorize will take a color and apply it to text. +This is used by the "color-*" role, and uses the LaTeX "xcolor" package. +For now, color should be assumed to be any string that xcolor allows, but +it's only been tested with the predefined color names: + black, blue, brown, cyan, darkgray, gray, green, lightgray, lime, magenta, + olive, orange, pink, purple, red, teal, violet, white, yellow +""" + + +def latex_colorize(color, text): + return latex_inline("\\textcolor{" + color + "}{" + latex_escape(text) + "}") + + ############################# ## PANDOC HELPER FUNCTIONS ## ############################# @@ -733,6 +747,15 @@ def pandoc_format(function_name, ast_string_node): def perform_role(role, literal_text, format): function_name = role_format_functions.get(role, None) + + # This allows us to define roles for color on the fly, + # just by prefixing the color we want with "color-". + # So to write "This is a red word" where 'red' is actually + # red you would write: + # This is a :color-red:`red` word + if role.startswith("color-"): + return latex_colorize(role[6:], literal_text) + if function_name == None: return function_name elif function_name in dir(pandocfilters): From c4187f2cfcde381e8d6f2fe3d7c607a1dba2686e Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Tue, 10 Dec 2024 15:19:41 +0000 Subject: [PATCH 09/11] Resolve "Break 160_genericity into chapters" --- .../160_genericity-intro.rst | 40 ++ .../fundamentals_of_ada/160_genericity.rst | 672 ++---------------- .../160_genericity/01-introduction.rst | 99 +++ .../160_genericity/02-creating_generics.rst | 77 ++ .../160_genericity/03-generic_data.rst | 105 +++ .../03-generic_data_in_depth.rst | 145 ++++ .../160_genericity/04-generic_formal_data.rst | 68 ++ .../04-generic_formal_data_in_depth.rst | 184 +++++ .../160_genericity/05-generic_completion.rst | 63 ++ .../160_genericity/99-summary.rst | 53 ++ .../intro_160_genericity.rst | 382 ---------- 11 files changed, 876 insertions(+), 1012 deletions(-) create mode 100644 courses/fundamentals_of_ada/160_genericity-intro.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/01-introduction.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/03-generic_data.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst create mode 100644 courses/fundamentals_of_ada/160_genericity/99-summary.rst delete mode 100644 courses/fundamentals_of_ada/intro_160_genericity.rst diff --git a/courses/fundamentals_of_ada/160_genericity-intro.rst b/courses/fundamentals_of_ada/160_genericity-intro.rst new file mode 100644 index 000000000..a4f4785bd --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity-intro.rst @@ -0,0 +1,40 @@ +************ +Genericity +************ + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 160_genericity/01-introduction.rst +.. include:: 160_genericity/02-creating_generics.rst +.. include:: 160_genericity/03-generic_data.rst +.. include:: 160_genericity/04-generic_formal_data.rst +.. include:: 160_genericity/99-summary.rst diff --git a/courses/fundamentals_of_ada/160_genericity.rst b/courses/fundamentals_of_ada/160_genericity.rst index d7eac0b1f..9a27b617b 100644 --- a/courses/fundamentals_of_ada/160_genericity.rst +++ b/courses/fundamentals_of_ada/160_genericity.rst @@ -1,630 +1,42 @@ -************ -Genericity -************ - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - -------------------------- -The Notion of a Pattern -------------------------- - -* Sometimes algorithms can be abstracted from types and subprograms - - .. code:: Ada - - procedure Swap_Int (Left, Right : in out Integer) is - V : Integer := Left; - begin - Left := Right; - Right := V; - end Swap_Int; - - procedure Swap_Bool (Left, Right : in out Boolean) is - V : Boolean := Left; - begin - Left := Right; - Right := V; - end Swap_Bool; - -* It would be nice to extract these properties in some common pattern, and then just replace the parts that need to be replaced - - .. code:: Ada - - procedure Swap (Left, Right : in out (Integer | Boolean)) is - V : (Integer | Boolean) := Left; - begin - Left := Right; - Right := V; - end Swap; - --------------------- -Solution: Generics --------------------- - -* A :dfn:`generic unit` is a unit that does not exist -* It is a pattern based on properties -* The instantiation applies the pattern to certain parameters - --------------------------------------- -Ada Generic Compared to C++ Template --------------------------------------- - -.. container:: columns - - .. container:: column - - Ada Generic - - .. container:: latex_environment scriptsize - - .. code:: Ada - - -- specification - generic - type T is private; - procedure Swap (L, R : in out T); - - -- implementation - procedure Swap (L, R : in out T) is - Tmp : T := L; - begin - L := R; - R := Tmp; - end Swap; - - -- instance - procedure Swap_F is new Swap (Float); - - .. container:: column - - C++ Template - - .. container:: latex_environment scriptsize - - .. code:: C++ - - // prototype - template - void Swap (T & L, T & R); - - // implementation - template - void Swap (T & L, T & R) { - T Tmp = L; - L = R; - R = Tmp; - } - - // instance - int x, y; - Swap(x,y); - -=================== -Creating Generics -=================== - ---------------------------- -What Can Be Made Generic? ---------------------------- - -* Subprograms and packages can be made generic - - .. code:: Ada - - generic - type T is private; - procedure Swap (L, R : in out T) - generic - type T is private; - package Stack is - procedure Push (Item : T); - ... - -* Children of generic units have to be generic themselves - - .. code:: Ada - - generic - package Stack.Utilities is - procedure Print (S : Stack_T); - ---------------------------- -How Do You Use a Generic? ---------------------------- - -* Generic instantiation is creating new set of data where a generic package contains library-level variables: - -.. code:: Ada - - package Integer_Stack is new Stack (Integer); - package Integer_Stack_Utils is - new Integer_Stack.Utilities; - ... - Integer_Stack.Push (S, 1); - Integer_Stack_Utils.Print (S); - -============== -Generic Data -============== - --------------------------------- -Generic Types Parameters (1/3) --------------------------------- - -* A generic parameter is a template -* It specifies the properties the generic body can rely on - - .. code:: Ada - - generic - type T1 is private; - type T2 (<>) is private; - type T3 is limited private; - package Parent is - -* The actual parameter must be no more restrictive then the :dfn:`generic contract` - ---------------------------------------- -Generic Types Parameters (2/3) ---------------------------------------- - -* Generic formal parameter tells generic what it is allowed to do with the type - -.. container:: latex_environment tiny - - .. list-table:: - - * - :ada:`type T1 is (<>);` - - - Discrete type; :ada:`'First`, :ada:`'Succ`, etc available - - * - :ada:`type T2 is range <>;` - - - Signed Integer type; appropriate mathematic operations allowed - - * - :ada:`type T3 is digits <>;` - - - Floating point type; appropriate mathematic operations allowed - - * - :ada:`type T4;` - - - Incomplete type; can only be used as target of :ada:`access` - - * - :ada:`type T5 is tagged private;` - - - :ada:`tagged` type; can extend the type - - * - :ada:`type T6 is private;` - - - No knowledge about the type other than assignment, comparison, object creation allowed - - * - :ada:`type T7 (<>) is private;` - - - :ada:`(<>)` indicates type can be unconstrained, so any object has to be initialized - --------------------------------- -Generic Types Parameters (3/3) --------------------------------- - -* The usage in the generic has to follow the contract - - * Generic Subprogram - - .. code:: Ada - - generic - type T (<>) is private; - procedure P (V : T); - procedure P (V : T) is - X1 : T := V; -- OK, can constrain by initialization - X2 : T; -- Compilation error, no constraint to this - begin - - * Instantiations - - .. code:: Ada - - type Limited_T is limited null record; - - -- unconstrained types are accepted - procedure P1 is new P (String); - - -- type is already constrained - -- (but generic will still always initialize objects) - procedure P2 is new P (Integer); - - -- Illegal: the type can't be limited because the generic - -- thinks it can make copies - procedure P3 is new P (Limited_T); - ------------------------------------- -Generic Parameters Can Be Combined ------------------------------------- - -* Consistency is checked at compile-time - -.. code:: Ada - - generic - type T (<>) is private; - type Acc is access all T; - type Index is (<>); - type Arr is array (Index range <>) of Acc; - function Element (Source : Arr; - Position : Index) - return T; - - type String_Ptr is access all String; - type String_Array is array (Integer range <>) - of String_Ptr; - - function String_Element is new Element - (T => String, - Acc => String_Ptr, - Index => Integer, - Arr => String_Array); - ------- -Quiz ------- - -.. code:: Ada - - generic - type T1 is (<>); - type T2 (<>) is private; - procedure G - (A : T1; - B : T2); - -Which is (are) legal instantiation(s)? - - A. ``procedure A is new G (String, Character);`` - B. :answermono:`procedure B is new G (Character, Integer);` - C. :answermono:`procedure C is new G (Integer, Boolean);` - D. :answermono:`procedure D is new G (Boolean, String);` - -.. container:: animate - - :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type - -===================== -Generic Formal Data -===================== - --------------------------------------------- -Generic Constants/Variables As Parameters --------------------------------------------- - -.. container:: columns - - .. container:: column - - * Variables can be specified on the generic contract - * The mode specifies the way the variable can be used: - - - :ada:`in` |rightarrow| read only - - :ada:`in out` |rightarrow| read write - - * Generic variables can be defined after generic types - - .. container:: column - - .. container:: latex_environment tiny - - * Generic package - - .. code:: Ada - - generic - type Element_T is private; - Array_Size : Positive; - High_Watermark : in out Element_T; - package Repository is - - * Generic instance - - .. code:: Ada - - V : Float; - Max : Float; - - procedure My_Repository is new Repository - (Element_T => Float, - Array_size => 10, - High_Watermark => Max); - -------------------------------- -Generic Subprogram Parameters -------------------------------- - -* Subprograms can be defined in the generic contract -* Must be introduced by :ada:`with` to differ from the generic unit - - .. code:: Ada - - generic - type T is private; - with function Less_Than (L, R : T) return Boolean; - function Max (L, R : T) return T; - - function Max (L, R : T) return T is - begin - if Less_Than (L, R) then - return R; - else - return L; - end if; - end Max; - - type Something_T is null record; - function Less_Than (L, R : Something_T) return Boolean; - procedure My_Max is new Max (Something_T, Less_Than); - ----------------------------------------- -Generic Subprogram Parameters Defaults ----------------------------------------- - -* :ada:`is <>` - matching subprogram is taken by default -* :ada:`is null` - null procedure is taken by default - - - Only available in Ada 2005 and later - - .. code:: Ada - - generic - type T is private; - with function Is_Valid (P : T) return Boolean is <>; - with procedure Error_Message (P : T) is null; - procedure Validate (P : T); - - function Is_Valid_Record (P : Record_T) return Boolean; - - procedure My_Validate is new Validate (Record_T, - Is_Valid_Record); - -- Is_Valid maps to Is_Valid_Record - -- Error_Message maps to a null procedure - -.. - language_version 2005 - ------- -Quiz ------- - -.. include:: quiz/genericity_type_and_variable/quiz.rst - ------- -Quiz ------- - -.. container:: columns - - .. container:: column - - - .. code:: Ada - :number-lines: 1 - - procedure Double (X : in out Integer); - procedure Square (X : in out Integer); - procedure Half (X : in out Integer); - generic - with procedure Double (X : in out Integer) is <>; - with procedure Square (X : in out Integer) is null; - procedure Math (P : in out Integer); - procedure Math (P : in out Integer) is - begin - Double (P); - Square (P); - end Math; - procedure Instance is new Math (Double => Half); - Number : Integer := 10; - - .. container:: column - - .. container:: column - - What is the value of Number after calling :ada:`Instance (Number)` - - A. 20 - B. 400 - C. :answer:`5` - D. 10 - -.. container:: animate - - A. Would be correct for :ada:`procedure Instance is new Math;` - - B. Would be correct for either :ada:`procedure Instance is new Math (Double, Square);` *or* :ada:`procedure Instance is new Math (Square => Square);` - - C. Correct - - * We call formal parameter :ada:`Double`, which has been assigned to actual subprogram :ada:`Half`, so :ada:`P`, which is 10, is halved. - - * Then we call formal parameter :ada:`Square`, which has no actual subprogram, so it defaults to :ada:`null`, so nothing happens to :ada:`P` - - D. Would be correct for either :ada:`procedure Instance is new Math (Double, Half);` *or* :ada:`procedure Instance is new Math (Square => Half);` - -.. - language_version 2005 - ----------------------- -Quiz Answer in Depth ----------------------- - - A. Wrong - result for :ada:`procedure Instance is new Math;` - B. Wrong - result for :ada:`procedure Instance is new Math (Double, Square);` - C. :ada:`Double` at line 10 is mapped to :ada:`Half` at line 3, and :ada:`Square` at line 11 wasn't specified so it defaults to :ada:`null` - D. Wrong - result for :ada:`procedure Instance is new Math (Square => Half);` - -.. container:: animate - - .. container:: latex_environment tiny - - :ada:`Math` is going to call two subprograms in order, :ada:`Double` and :ada:`Square`, but both of those come from the formal data. - - Whatever is used for :ada:`Double`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler tries to find a subprogram named :ada:`Double` and use that. If it doesn't, that's a compile error. - - Whatever is used for :ada:`Square`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler will treat this as a null call. - - In our case, :ada:`Half` is passed in for the first subprogram, but nothing is passed in for the second, so that call will just be null. - - So the final answer should be 5 (hence letter C). - -==================== -Generic Completion -==================== - ------------------------------- -Implications at Compile-Time ------------------------------- - -* The body needs to be visible when compiling the user code -* Therefore, when distributing a component with generics to be instantiated, the code of the generic must come along - ------------------------------ -Generic and Freezing Points ------------------------------ - -* A generic type **freezes** the type and needs the **full view** -* May force separation between its declaration (in spec) and instantiations (in private or body) - -.. code:: Ada - - generic - type X is private; - package Base is - V : access X; - end Base; - - package P is - type X is private; - -- illegal - package B is new Base (X); - private - type X is null record; - end P; - -------------------------------- -Generic Incomplete Parameters -------------------------------- - -* A generic type can be incomplete -* Allows generic instantiations before full type definition -* Restricts the possible usages (only :ada:`access`) - -.. code:: Ada - - generic - type X; -- incomplete - package Base is - V : access X; - end Base; - - package P is - type X is private; - -- legal - package B is new Base (X); - private - type X is null record; - end P; - ------- -Quiz ------- - -.. include:: quiz/genericity_private_type/quiz.rst - -======== -Lab -======== - -.. include:: labs/160_genericity.lab.rst - -========= -Summary -========= - -------------------------------------- -Generic Routines Vs Common Routines -------------------------------------- - -.. code:: Ada - - package Helper is - type Float_T is digits 6; - generic - type Type_T is digits <>; - Min : Type_T; - Max : Type_T; - function In_Range_Generic (X : Type_T) return Boolean; - function In_Range_Common (X : Float_T; - Min : Float_T; - Max : Float_T) - return Boolean; - end Helper; - - procedure User is - type Speed_T is new Float_T range 0.0 .. 100.0; - B : Boolean; - function Valid_Speed is new In_Range_Generic - (Speed_T, Speed_T'First, Speed_T'Last); - begin - B := Valid_Speed (12.3); - B := In_Range_Common (12.3, Speed_T'First, Speed_T'Last); - -.. container:: speakernote - - Generics increase code size and readability - Common functions reduce size, but increase error possibilities - ---------- -Summary ---------- - -* Generics are useful for copying code that works the same just for different types - - - Sorting, containers, etc - -* Properly written generics only need to be tested once - - - But testing / debugging can be more difficult - -* Generic instantiations are best done at compile time - - - At the package level - - Can be run time expensive when done in subprogram scope +************ +Genericity +************ + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 160_genericity/01-introduction.rst +.. include:: 160_genericity/02-creating_generics.rst +.. include:: 160_genericity/03-generic_data_in_depth.rst +.. include:: 160_genericity/04-generic_formal_data_in_depth.rst +.. include:: 160_genericity/05-generic_completion.rst +.. include:: labs/160_genericity.lab.rst +.. include:: 160_genericity/99-summary.rst diff --git a/courses/fundamentals_of_ada/160_genericity/01-introduction.rst b/courses/fundamentals_of_ada/160_genericity/01-introduction.rst new file mode 100644 index 000000000..9f87959df --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/01-introduction.rst @@ -0,0 +1,99 @@ +============== +Introduction +============== + +------------------------- +The Notion of a Pattern +------------------------- + +* Sometimes algorithms can be abstracted from types and subprograms + + .. code:: Ada + + procedure Swap_Int (Left, Right : in out Integer) is + V : Integer := Left; + begin + Left := Right; + Right := V; + end Swap_Int; + + procedure Swap_Bool (Left, Right : in out Boolean) is + V : Boolean := Left; + begin + Left := Right; + Right := V; + end Swap_Bool; + +* It would be nice to extract these properties in some common pattern, and then just replace the parts that need to be replaced + + .. code:: Ada + + procedure Swap (Left, Right : in out (Integer | Boolean)) is + V : (Integer | Boolean) := Left; + begin + Left := Right; + Right := V; + end Swap; + +-------------------- +Solution: Generics +-------------------- + +* A :dfn:`generic unit` is a unit that does not exist +* It is a pattern based on properties +* The instantiation applies the pattern to certain parameters + +-------------------------------------- +Ada Generic Compared to C++ Template +-------------------------------------- + +.. container:: columns + + .. container:: column + + Ada Generic + + .. container:: latex_environment scriptsize + + .. code:: Ada + + -- specification + generic + type T is private; + procedure Swap (L, R : in out T); + + -- implementation + procedure Swap (L, R : in out T) is + Tmp : T := L; + begin + L := R; + R := Tmp; + end Swap; + + -- instance + procedure Swap_F is new Swap (Float); + + .. container:: column + + C++ Template + + .. container:: latex_environment scriptsize + + .. code:: C++ + + // prototype + template + void Swap (T & L, T & R); + + // implementation + template + void Swap (T & L, T & R) { + T Tmp = L; + L = R; + R = Tmp; + } + + // instance + int x, y; + Swap(x,y); + diff --git a/courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst b/courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst new file mode 100644 index 000000000..483ea69d0 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/02-creating_generics.rst @@ -0,0 +1,77 @@ +=================== +Creating Generics +=================== + +------------- +Declaration +------------- + +* Subprograms + + .. code:: Ada + + generic + type T is private; + procedure Swap (L, R : in out T); + +* Packages + + .. code:: Ada + + generic + type T is private; + package Stack is + procedure Push (Item : T); + end Stack; + +* Body is required + + - Will be specialized and compiled for **each instance** + +* Children of generic units have to be generic themselves + + .. code:: Ada + + generic + package Stack.Utilities is + procedure Print (S : Stack_T); + +------- +Usage +------- + +* Instantiated with the :ada:`new` keyword + +.. code:: Ada + + -- Standard library + function Convert is new Ada.Unchecked_Conversion + (Integer, Array_Of_4_Bytes); + -- Callbacks + procedure Parse_Tree is new Tree_Parser + (Visitor_Procedure); + -- Containers, generic data-structures + package Integer_Stack is new Stack (Integer); + +* Advanced usages for testing, proof, meta-programming + +------ +Quiz +------ + +Which one(s) of the following can be made generic? + +.. code:: Ada + + generic + type T is private; + + +A. :answermono:`package` +B. ``record`` +D. :answermono:`function` +C. ``array`` + +.. container:: animate + + Only packages, functions, and procedures, can be made generic. diff --git a/courses/fundamentals_of_ada/160_genericity/03-generic_data.rst b/courses/fundamentals_of_ada/160_genericity/03-generic_data.rst new file mode 100644 index 000000000..405b515c8 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/03-generic_data.rst @@ -0,0 +1,105 @@ +============== +Generic Data +============== + +------------- +Definitions +------------- + +* A formal generic parameter is a template +* Properties are either :dfn:`constraints` or :dfn:`capabilities` + + - Expressed from the **body** point of view + - Constraints: e.g. unconstrained, :ada:`limited` + - Capabilities: e.g. :ada:`tagged`, primitives + +.. code:: Ada + + generic + type Pv is private; -- allocation, copy, assignment, "=" + with procedure Sort (T : Pv); -- primitive of Pv + type Unc (<>) is private; -- allocation require a value + type Lim is limited private; -- no copy or comparison + type Disc is (<>); -- 'First, ordering + package Generic_Pkg is [...] + +* Actual parameter **may** require constraints, and **must** provide capabilities + +.. code:: Ada + + package Pkg is new Generic_Pkg ( + Pv => Integer, -- has capabilities of private + Sort => Sort -- procedure Sort (T : Integer) + Unc => String, -- uses "unconstrained" constraint + Lim => Float, -- does not use "limited" constraint + Disc => Boolean, -- has capability of discrete + ); + +------------------ +Syntax (partial) +------------------ + +.. code:: Ada + + type T1 is (<>); -- discrete + type T2 is range <>; -- Integer + type T3 is digits <>; -- float + type T4 is private; -- indefinite + type T5 (<>) is private; -- indefinite + type T6 is tagged private; + type T7 is array (Boolean) of Integer; + type T8 is access Integer; + type T9 is limited private; + +* Not limited to those choices + +.. code:: Ada + + type T is not null access all limited tagged private; + +------ +Quiz +------ + +Which of the following statement is true? + +A. Generic contracts define new types +B. Generic contracts can express any type constraint +C. :answer:`Generic contracts can express inheritance constraint` +D. Generic contracts can require a type to be numeric (:ada:`Real` or :ada:`Integer`) + +.. container:: animate + + A. No, the formal type and the actual type just have different views + B. Counter-example: representation clauses + +------ +Quiz +------ + +.. include:: ../quiz/generic_subp_syntax/quiz.rst + +------ +Quiz +------ + +.. code:: Ada + + generic + type T1 is (<>); + type T2 (<>) is private; + procedure G + (A : T1; + B : T2); + +Which is (are) legal instantiation(s)? + + A. ``procedure A is new G (String, Character);`` + B. :answermono:`procedure B is new G (Character, Integer);` + C. :answermono:`procedure C is new G (Integer, Boolean);` + D. :answermono:`procedure D is new G (Boolean, String);` + +.. container:: animate + + :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type + diff --git a/courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst b/courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst new file mode 100644 index 000000000..e0d7c76b6 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/03-generic_data_in_depth.rst @@ -0,0 +1,145 @@ +============== +Generic Data +============== + +-------------------------------- +Generic Types Parameters (1/3) +-------------------------------- + +* A generic parameter is a template +* It specifies the properties the generic body can rely on + + .. code:: Ada + + generic + type T1 is private; + type T2 (<>) is private; + type T3 is limited private; + package Parent is + +* The actual parameter must be no more restrictive then the :dfn:`generic contract` + +--------------------------------------- +Generic Types Parameters (2/3) +--------------------------------------- + +* Generic formal parameter tells generic what it is allowed to do with the type + +.. container:: latex_environment tiny + + .. list-table:: + + * - :ada:`type T1 is (<>);` + + - Discrete type; :ada:`'First`, :ada:`'Succ`, etc available + + * - :ada:`type T2 is range <>;` + + - Signed Integer type; appropriate mathematic operations allowed + + * - :ada:`type T3 is digits <>;` + + - Floating point type; appropriate mathematic operations allowed + + * - :ada:`type T4;` + + - Incomplete type; can only be used as target of :ada:`access` + + * - :ada:`type T5 is tagged private;` + + - :ada:`tagged` type; can extend the type + + * - :ada:`type T6 is private;` + + - No knowledge about the type other than assignment, comparison, object creation allowed + + * - :ada:`type T7 (<>) is private;` + + - :ada:`(<>)` indicates type can be unconstrained, so any object has to be initialized + +-------------------------------- +Generic Types Parameters (3/3) +-------------------------------- + +* The usage in the generic has to follow the contract + + * Generic Subprogram + + .. code:: Ada + + generic + type T (<>) is private; + procedure P (V : T); + procedure P (V : T) is + X1 : T := V; -- OK, can constrain by initialization + X2 : T; -- Compilation error, no constraint to this + begin + + * Instantiations + + .. code:: Ada + + type Limited_T is limited null record; + + -- unconstrained types are accepted + procedure P1 is new P (String); + + -- type is already constrained + -- (but generic will still always initialize objects) + procedure P2 is new P (Integer); + + -- Illegal: the type can't be limited because the generic + -- thinks it can make copies + procedure P3 is new P (Limited_T); + +------------------------------------ +Generic Parameters Can Be Combined +------------------------------------ + +* Consistency is checked at compile-time + +.. code:: Ada + + generic + type T (<>) is private; + type Acc is access all T; + type Index is (<>); + type Arr is array (Index range <>) of Acc; + function Element (Source : Arr; + Position : Index) + return T; + + type String_Ptr is access all String; + type String_Array is array (Integer range <>) + of String_Ptr; + + function String_Element is new Element + (T => String, + Acc => String_Ptr, + Index => Integer, + Arr => String_Array); + +------ +Quiz +------ + +.. code:: Ada + + generic + type T1 is (<>); + type T2 (<>) is private; + procedure G + (A : T1; + B : T2); + +Which is (are) legal instantiation(s)? + + A. ``procedure A is new G (String, Character);`` + B. :answermono:`procedure B is new G (Character, Integer);` + C. :answermono:`procedure C is new G (Integer, Boolean);` + D. :answermono:`procedure D is new G (Boolean, String);` + +.. container:: animate + + :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type + diff --git a/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst new file mode 100644 index 000000000..adcc50b35 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data.rst @@ -0,0 +1,68 @@ +===================== +Generic Formal Data +===================== + +-------------------------------------------- +Generic Constants and Variables Parameters +-------------------------------------------- + +.. container:: columns + + .. container:: column + + * Variables can be specified on the generic contract + * The mode specifies the way the variable can be used: + + - :ada:`in` |rightarrow| read only + - :ada:`in out` |rightarrow| read write + + * Generic variables can be defined after generic types + + .. container:: column + + .. code:: Ada + + generic + type T is private; + X1 : Integer; -- constant + X2 : in out T; -- variable + procedure P; + + V : Float; + + procedure P_I is new P + (T => Float, + X1 => 42, + X2 => V); + +------------------------------- +Generic Subprogram Parameters +------------------------------- + +* Subprograms can be defined in the generic contract +* Must be introduced by :ada:`with` to differ from the generic unit + + .. code:: Ada + + generic + with procedure Callback; + procedure P; + procedure P is + begin + Callback; + end P; + procedure Something is null; + procedure P_I is new P (Something); + +------ +Quiz +------ + +.. include:: ../quiz/genericity_type_and_variable/quiz.rst + +------ +Quiz +------ + +.. include:: ../quiz/genericity_limited_type/quiz.rst + diff --git a/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst new file mode 100644 index 000000000..1d65e1fb3 --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/04-generic_formal_data_in_depth.rst @@ -0,0 +1,184 @@ +===================== +Generic Formal Data +===================== + +-------------------------------------------- +Generic Constants/Variables As Parameters +-------------------------------------------- + +.. container:: columns + + .. container:: column + + * Variables can be specified on the generic contract + * The mode specifies the way the variable can be used: + + - :ada:`in` |rightarrow| read only + - :ada:`in out` |rightarrow| read write + + * Generic variables can be defined after generic types + + .. container:: column + + .. container:: latex_environment tiny + + * Generic package + + .. code:: Ada + + generic + type Element_T is private; + Array_Size : Positive; + High_Watermark : in out Element_T; + package Repository is + + * Generic instance + + .. code:: Ada + + V : Float; + Max : Float; + + procedure My_Repository is new Repository + (Element_T => Float, + Array_size => 10, + High_Watermark => Max); + +------------------------------- +Generic Subprogram Parameters +------------------------------- + +* Subprograms can be defined in the generic contract +* Must be introduced by :ada:`with` to differ from the generic unit + + .. code:: Ada + + generic + type T is private; + with function Less_Than (L, R : T) return Boolean; + function Max (L, R : T) return T; + + function Max (L, R : T) return T is + begin + if Less_Than (L, R) then + return R; + else + return L; + end if; + end Max; + + type Something_T is null record; + function Less_Than (L, R : Something_T) return Boolean; + procedure My_Max is new Max (Something_T, Less_Than); + +---------------------------------------- +Generic Subprogram Parameters Defaults +---------------------------------------- + +* :ada:`is <>` - matching subprogram is taken by default +* :ada:`is null` - null procedure is taken by default + + - Only available in Ada 2005 and later + + .. code:: Ada + + generic + type T is private; + with function Is_Valid (P : T) return Boolean is <>; + with procedure Error_Message (P : T) is null; + procedure Validate (P : T); + + function Is_Valid_Record (P : Record_T) return Boolean; + + procedure My_Validate is new Validate (Record_T, + Is_Valid_Record); + -- Is_Valid maps to Is_Valid_Record + -- Error_Message maps to a null procedure + +.. + language_version 2005 + +------ +Quiz +------ + +.. include:: ../quiz/genericity_type_and_variable/quiz.rst + +------ +Quiz +------ + +.. container:: columns + + .. container:: column + + + .. code:: Ada + :number-lines: 1 + + procedure Double (X : in out Integer); + procedure Square (X : in out Integer); + procedure Half (X : in out Integer); + generic + with procedure Double (X : in out Integer) is <>; + with procedure Square (X : in out Integer) is null; + procedure Math (P : in out Integer); + procedure Math (P : in out Integer) is + begin + Double (P); + Square (P); + end Math; + procedure Instance is new Math (Double => Half); + Number : Integer := 10; + + .. container:: column + + .. container:: column + + What is the value of Number after calling :ada:`Instance (Number)` + + A. 20 + B. 400 + C. :answer:`5` + D. 10 + +.. container:: animate + + A. Would be correct for :ada:`procedure Instance is new Math;` + + B. Would be correct for either :ada:`procedure Instance is new Math (Double, Square);` *or* :ada:`procedure Instance is new Math (Square => Square);` + + C. Correct + + * We call formal parameter :ada:`Double`, which has been assigned to actual subprogram :ada:`Half`, so :ada:`P`, which is 10, is halved. + + * Then we call formal parameter :ada:`Square`, which has no actual subprogram, so it defaults to :ada:`null`, so nothing happens to :ada:`P` + + D. Would be correct for either :ada:`procedure Instance is new Math (Double, Half);` *or* :ada:`procedure Instance is new Math (Square => Half);` + +.. + language_version 2005 + +---------------------- +Quiz Answer in Depth +---------------------- + + A. Wrong - result for :ada:`procedure Instance is new Math;` + B. Wrong - result for :ada:`procedure Instance is new Math (Double, Square);` + C. :ada:`Double` at line 10 is mapped to :ada:`Half` at line 3, and :ada:`Square` at line 11 wasn't specified so it defaults to :ada:`null` + D. Wrong - result for :ada:`procedure Instance is new Math (Square => Half);` + +.. container:: animate + + .. container:: latex_environment tiny + + :ada:`Math` is going to call two subprograms in order, :ada:`Double` and :ada:`Square`, but both of those come from the formal data. + + Whatever is used for :ada:`Double`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler tries to find a subprogram named :ada:`Double` and use that. If it doesn't, that's a compile error. + + Whatever is used for :ada:`Square`, will be called by the :ada:`Math` instance. If nothing is passed in, the compiler will treat this as a null call. + + In our case, :ada:`Half` is passed in for the first subprogram, but nothing is passed in for the second, so that call will just be null. + + So the final answer should be 5 (hence letter C). + diff --git a/courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst b/courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst new file mode 100644 index 000000000..dc7a55bac --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/05-generic_completion.rst @@ -0,0 +1,63 @@ +==================== +Generic Completion +==================== + +------------------------------ +Implications at Compile-Time +------------------------------ + +* The body needs to be visible when compiling the user code +* Therefore, when distributing a component with generics to be instantiated, the code of the generic must come along + +----------------------------- +Generic and Freezing Points +----------------------------- + +* A generic type **freezes** the type and needs the **full view** +* May force separation between its declaration (in spec) and instantiations (in private or body) + +.. code:: Ada + + generic + type X is private; + package Base is + V : access X; + end Base; + + package P is + type X is private; + -- illegal + package B is new Base (X); + private + type X is null record; + end P; + +------------------------------- +Generic Incomplete Parameters +------------------------------- + +* A generic type can be incomplete +* Allows generic instantiations before full type definition +* Restricts the possible usages (only :ada:`access`) + +.. code:: Ada + + generic + type X; -- incomplete + package Base is + V : access X; + end Base; + + package P is + type X is private; + -- legal + package B is new Base (X); + private + type X is null record; + end P; + +------ +Quiz +------ + +.. include:: ../quiz/genericity_private_type/quiz.rst diff --git a/courses/fundamentals_of_ada/160_genericity/99-summary.rst b/courses/fundamentals_of_ada/160_genericity/99-summary.rst new file mode 100644 index 000000000..8d193c31a --- /dev/null +++ b/courses/fundamentals_of_ada/160_genericity/99-summary.rst @@ -0,0 +1,53 @@ +========= +Summary +========= + +------------------------------------- +Generic Routines Vs Common Routines +------------------------------------- + +.. code:: Ada + + package Helper is + type Float_T is digits 6; + generic + type Type_T is digits <>; + Min : Type_T; + Max : Type_T; + function In_Range_Generic (X : Type_T) return Boolean; + function In_Range_Common (X : Float_T; + Min : Float_T; + Max : Float_T) + return Boolean; + end Helper; + + procedure User is + type Speed_T is new Float_T range 0.0 .. 100.0; + B : Boolean; + function Valid_Speed is new In_Range_Generic + (Speed_T, Speed_T'First, Speed_T'Last); + begin + B := Valid_Speed (12.3); + B := In_Range_Common (12.3, Speed_T'First, Speed_T'Last); + +.. container:: speakernote + + Generics increase code size and readability + Common functions reduce size, but increase error possibilities + +--------- +Summary +--------- + +* Generics are useful for copying code that works the same just for different types + + - Sorting, containers, etc + +* Properly written generics only need to be tested once + + - But testing / debugging can be more difficult + +* Generic instantiations are best done at compile time + + - At the package level + - Can be run time expensive when done in subprogram scope diff --git a/courses/fundamentals_of_ada/intro_160_genericity.rst b/courses/fundamentals_of_ada/intro_160_genericity.rst deleted file mode 100644 index 7a12f82b9..000000000 --- a/courses/fundamentals_of_ada/intro_160_genericity.rst +++ /dev/null @@ -1,382 +0,0 @@ -************ -Genericity -************ - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - -------------------------- -The Notion of a Pattern -------------------------- - -* Sometimes algorithms can be abstracted from types and subprograms - - .. code:: Ada - - procedure Swap_Int (Left, Right : in out Integer) is - V : Integer; - begin - V := Left; - Left := Right; - Right := V; - end Swap_Int; - - procedure Swap_Bool (Left, Right : in out Boolean) is - V : Boolean; - begin - V := Left; - Left := Right; - Right := V; - end Swap_Bool; - -* It would be nice to extract these properties in some common pattern, and then just replace the parts that need to be replaced - - .. code:: Ada - - -- T := Integer | Boolean - procedure Swap (Left, Right : in out T) is - V : T; - begin - V := Left; - Left := Right; - Right := V; - end Swap; - --------------------- -Solution: Generics --------------------- - -* A :dfn:`generic unit` is a code pattern which can be reused - - - Does not get compiled as-is - -* The instantiation applies the pattern to certain parameters - - - Based on properties - - Use a :dfn:`generic contract` - - Parameters can be constant, variable, subprogram, type, package - -======== -Syntax -======== - -------- -Usage -------- - -* Instantiated with the :ada:`new` keyword - -.. code:: Ada - - -- Standard library - function Convert is new Ada.Unchecked_Conversion - (Integer, Array_Of_4_Bytes); - -- Callbacks - procedure Parse_Tree is new Tree_Parser - (Visitor_Procedure); - -- Containers, generic data-structures - package Integer_Stack is new Stack (Integer); - -* Advanced usages for testing, proof, meta-programming - -------------- -Declaration -------------- - -* Subprograms - - .. code:: Ada - - generic - type T is private; - procedure Swap (L, R : in out T); - -* Packages - - .. code:: Ada - - generic - type T is private; - package Stack is - procedure Push (Item : T); - end Stack; - -* Body is required - - - Will be specialized and compiled for **each instance** - ------- -Quiz ------- - -Which of the following statement is true? - -A. :answer:`Generics allow for code reuse` -B. :answer:`Generics can take packages as parameters` -C. Genericity is specific to Ada -D. :answer:`Genericity is available in all versions of Ada and/or SPARK` - ------- -Quiz ------- - -Which one(s) of the following can be made generic? - -.. code:: Ada - - generic - type T is private; - - -A. :answermono:`package` -B. ``record`` -D. :answermono:`function` -C. ``array`` - -.. container:: animate - - Only packages, functions, and procedures, can be made generic. - ------- -Quiz ------- - -Which of the following statement is true? - -A. Generic instances must be nested inside a non-generic package -B. Generic instances must be instantiated at compile-time -C. :answer:`Generics instances can create new tagged types` -D. :answer:`Generics instances can create new tasks` - -.. container:: animate - - Generic instances can be instantiated at any point, at a cost, and - can do anything a package or subprogram can do, which make them - versatile **but** potentially complex to use. - -=================== -Generic Contracts -=================== - -------------- -Definitions -------------- - -* A formal generic parameter is a template -* Properties are either :dfn:`constraints` or :dfn:`capabilities` - - - Expressed from the **body** point of view - - Constraints: e.g. unconstrained, :ada:`limited` - - Capabilities: e.g. :ada:`tagged`, primitives - -.. code:: Ada - - generic - type Pv is private; -- allocation, copy, assignment, "=" - with procedure Sort (T : Pv); -- primitive of Pv - type Unc (<>) is private; -- allocation require a value - type Lim is limited private; -- no copy or comparison - type Disc is (<>); -- 'First, ordering - package Generic_Pkg is [...] - -* Actual parameter **may** require constraints, and **must** provide capabilities - -.. code:: Ada - - package Pkg is new Generic_Pkg ( - Pv => Integer, -- has capabilities of private - Sort => Sort -- procedure Sort (T : Integer) - Unc => String, -- uses "unconstrained" constraint - Lim => Float, -- does not use "limited" constraint - Disc => Boolean, -- has capability of discrete - ); - ------------------- -Syntax (partial) ------------------- - -.. code:: Ada - - type T1 is (<>); -- discrete - type T2 is range <>; -- Integer - type T3 is digits <>; -- float - type T4 is private; -- indefinite - type T5 (<>) is private; -- indefinite - type T6 is tagged private; - type T7 is array (Boolean) of Integer; - type T8 is access Integer; - type T9 is limited private; - -* Not limited to those choices - -.. code:: Ada - - type T is not null access all limited tagged private; - ------- -Quiz ------- - -Which of the following statement is true? - -A. Generic contracts define new types -B. Generic contracts can express any type constraint -C. :answer:`Generic contracts can express inheritance constraint` -D. Generic contracts can require a type to be numeric (:ada:`Real` or :ada:`Integer`) - -.. container:: animate - - A. No, the formal type and the actual type just have different views - B. Counter-example: representation clauses - ------- -Quiz ------- - -.. include:: quiz/generic_subp_syntax/quiz.rst - ------- -Quiz ------- - -.. code:: Ada - - generic - type T1 is (<>); - type T2 (<>) is private; - procedure G - (A : T1; - B : T2); - -Which is (are) legal instantiation(s)? - - A. ``procedure A is new G (String, Character);`` - B. :answermono:`procedure B is new G (Character, Integer);` - C. :answermono:`procedure C is new G (Integer, Boolean);` - D. :answermono:`procedure D is new G (Boolean, String);` - -.. container:: animate - - :ada:`T1` must be discrete - so an integer or an enumeration. :ada:`T2` can be any type - -===================== -Generic Formal Data -===================== - --------------------------------------------- -Generic Constants and Variables Parameters --------------------------------------------- - -.. container:: columns - - .. container:: column - - * Variables can be specified on the generic contract - * The mode specifies the way the variable can be used: - - - :ada:`in` |rightarrow| read only - - :ada:`in out` |rightarrow| read write - - * Generic variables can be defined after generic types - - .. container:: column - - .. code:: Ada - - generic - type T is private; - X1 : Integer; -- constant - X2 : in out T; -- variable - procedure P; - - V : Float; - - procedure P_I is new P - (T => Float, - X1 => 42, - X2 => V); - -------------------------------- -Generic Subprogram Parameters -------------------------------- - -* Subprograms can be defined in the generic contract -* Must be introduced by :ada:`with` to differ from the generic unit - - .. code:: Ada - - generic - with procedure Callback; - procedure P; - procedure P is - begin - Callback; - end P; - procedure Something is null; - procedure P_I is new P (Something); - ------- -Quiz ------- - -.. include:: quiz/genericity_type_and_variable/quiz.rst - ------- -Quiz ------- - -.. include:: quiz/genericity_limited_type/quiz.rst - -========= -Summary -========= - ---------- -Summary ---------- - -* Generics are useful for **reusing code** - - - Sorting, containers, etc - -* Generic contracts syntax is different from Ada declaration - - - But has some resemblance to it - - e.g. discretes' :ada:`type Enum is (A, B, C)` vs generics' :ada:`type T is (<>)` - -* Instantiation "generates" code - - - Costly - - Beware of local generic instances! From 81d6cb60dfb757eb3818c51a2f1d286fe887316c Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Tue, 10 Dec 2024 21:20:55 +0000 Subject: [PATCH 10/11] Resolve "break 135_visibility into chapters" --- .../fundamentals_of_ada/135_visibility.rst | 542 ++---------------- .../135_visibility/01-introduction.rst | 41 ++ .../135_visibility/02-use_clauses.rst | 198 +++++++ .../03-use_type_and_use_all_type_clauses.rst | 89 +++ .../135_visibility/04-renaming_entities.rst | 115 ++++ .../135_visibility/05-lab.rst | 45 ++ .../135_visibility/99-summary.rst | 17 + .../labs/135_visibility.lab.rst | 4 + 8 files changed, 550 insertions(+), 501 deletions(-) create mode 100644 courses/fundamentals_of_ada/135_visibility/01-introduction.rst create mode 100644 courses/fundamentals_of_ada/135_visibility/02-use_clauses.rst create mode 100644 courses/fundamentals_of_ada/135_visibility/03-use_type_and_use_all_type_clauses.rst create mode 100644 courses/fundamentals_of_ada/135_visibility/04-renaming_entities.rst create mode 100644 courses/fundamentals_of_ada/135_visibility/05-lab.rst create mode 100644 courses/fundamentals_of_ada/135_visibility/99-summary.rst diff --git a/courses/fundamentals_of_ada/135_visibility.rst b/courses/fundamentals_of_ada/135_visibility.rst index 6497c0318..d6c5aeded 100644 --- a/courses/fundamentals_of_ada/135_visibility.rst +++ b/courses/fundamentals_of_ada/135_visibility.rst @@ -1,501 +1,41 @@ -************ -Visibility -************ - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - ------------------------ -Improving Readability ------------------------ - -* Descriptive names plus hierarchical packages makes for very long statements - - .. code:: - - Messages.Queue.Diagnostics.Inject_Fault ( - Fault => Messages.Queue.Diagnostics.CRC_Failure, - Position => Messages.Queue.Front); - -* Operators treated as functions defeat the purpose of overloading - - .. code:: - - Complex1 := Complex_Types."+" (Complex2, Complex3); - -* Ada has mechanisms to simplify hierarchies - --------------------------- -Operators and Primitives --------------------------- - -* :dfn:`Operators` - - - Constructs which behave generally like functions but which differ syntactically or semantically - - Typically arithmetic, comparison, and logical - -* **Primitive operation** - - - Predefined operations such as ``=`` and ``+`` etc. - - Subprograms declared in the same package as the type and which operate on the type - - Inherited or overridden subprograms - - For :ada:`tagged` types, class-wide subprograms - - Enumeration literals - -=============== -"use" Clauses -=============== - ---------------- -"use" Clauses ---------------- - -* :ada:`use Pkg;` provides direct visibility into public items in :ada:`Pkg` - - + :dfn:`Direct Visibility` - as if object was referenced from within package being used - + :dfn:`Public Items` - any entity defined in package spec public section - -* May still use expanded name - -.. code:: Ada - - package Ada.Text_IO is - procedure Put_Line (...); - procedure New_Line (...); - ... - end Ada.Text_IO; - - with Ada.Text_IO; - procedure Hello is - use Ada.Text_IO; - begin - Put_Line ("Hello World"); - New_Line (3); - Ada.Text_IO.Put_Line ("Good bye"); - end Hello; - ---------------------- -"use" Clause Syntax ---------------------- - -* May have several, like :ada:`with` clauses -* Can refer to any visible package (including nested packages) -* Syntax - - .. code:: Ada - - use_package_clause ::= use package_name {, package_name}; - -* Can only :ada:`use` a package - - - Subprograms have no contents to :ada:`use` - --------------------- -"use" Clause Scope --------------------- - -* Applies to end of body, from first occurrence - -.. code:: Ada - - package Pkg_A is - Constant_A : constant := 123; - end Pkg_A; - - package Pkg_B is - Constant_B : constant := 987; - end Pkg_B; - - with Pkg_A; - with Pkg_B; - use Pkg_A; -- everything in Pkg_A is now visible - package P is - A : Integer := Constant_A; -- legal - B1 : Integer := Constant_B; -- illegal - use Pkg_B; -- everything in Pkg_B is now visible - B2 : Integer := Constant_B; -- legal - function F return Integer; - end P; - - package body P is - -- all of Pkg_A and Pkg_B is visible here - function F return Integer is (Constant_A + Constant_B); - end P; - --------------------- -No Meaning Changes --------------------- - -* A new :ada:`use` clause won't change a program's meaning! -* Any directly visible names still refer to the original entities - -.. code:: Ada - - package D is - T : Float; - end D; - - with D; - procedure P is - procedure Q is - T, X : Float; - begin - ... - declare - use D; - begin - -- With or without the clause, "T" means Q.T - X := T; - end; - ... - end Q; - ---------------------------- -No Ambiguity Introduction ---------------------------- - -.. code:: Ada - - package D is - V : Boolean; - end D; - - package E is - V : Integer; - end E; - with D, E; - - procedure P is - procedure Q is - use D, E; - begin - -- to use V here, must specify D.V or E.V - ... - end Q; - begin - ... - -.. container:: speakernote - - For declarations in different packages that would not be directly visible in the absence of a "use" clause, none with the same identifier will be directly visible in the presence of such a clause, unless both are overloadable (i.e., enumeration literals and subprogram declarations) - ------------------------------- -"use" Clauses and Child Units ------------------------------- - -* A clause for a child does **not** imply one for its parent -* A clause for a parent makes the child **directly** visible - - - Since children are 'inside' declarative region of parent - -.. code:: Ada - - package Parent is - P1 : Integer; - end Parent; - - package Parent.Child is - PC1 : Integer; - end Parent.Child; - - with Parent; - with Parent.Child; use Parent.Child; - procedure Demo is - D1 : Integer := Parent.P1; - D2 : Integer := Parent.Child.PC1; - use Parent; - D3 : Integer := P1; -- illegal - D4 : Integer := PC1; - ... - -.. container:: speakernote - - D4 has access to CHILD because PARENT is "use"d - ----------------------------------------- -"use" Clause and Implicit Declarations ----------------------------------------- - -* Visibility rules apply to implicit declarations too - -.. code:: Ada - - package P is - type Int is range Lower .. Upper; - -- implicit declarations - -- function "+"(Left, Right : Int) return Int; - -- function "="(Left, Right : Int) return Boolean; - end P; - - with P; - procedure Test is - A, B, C : P.Int := some_value; - begin - C := A + B; -- illegal reference to operator - C := P."+" (A,B); - declare - use P; - begin - C := A + B; -- now legal - end; - end Test; - -======================================= -"use type" and "use all type" Clauses -======================================= - -------------------------------- -"use type" and "use all type" -------------------------------- - -* :ada:`use type` makes **primitive operators** directly visible for specified type - - - Implicit and explicit operator function declarations - - .. code:: Ada - - use type subtype_mark {, subtype_mark}; - -* :ada:`use all type` makes primitive operators **and all other operations** directly visible for specified type - - - All **enumerated type values** will also be directly visible - - .. code:: Ada - - use all type subtype_mark {, subtype_mark}; - -* More specific alternatives to :ada:`use` clauses - - - Especially useful when multiple :ada:`use` clauses introduce ambiguity - --------------- -Example Code --------------- - -.. code:: Ada - - package Types is - type Distance_T is range 0 .. Integer'Last; - - -- explicit declaration - -- (we don't want a negative distance) - function "-" (Left, Right : Distance_T) - return Distance_T; - - -- implicit declarations (we get the division operator - -- for "free", showing it for completeness) - -- function "/" (Left, Right : Distance_T) return - -- Distance_T; - - -- primitive operation - function Min (A, B : Distance_T) - return Distance_T; - - end Types; - --------------------------- -"use" Clauses Comparison --------------------------- - -.. image:: use_clause_comparison.png - ------------------------------ -Multiple "use type" Clauses ------------------------------ - -* May be necessary -* Only those that mention the type in their profile are made visible - -.. code:: Ada - - package P is - type T1 is range 1 .. 10; - type T2 is range 1 .. 10; - -- implicit - -- function "+"(Left : T2; Right : T2) return T2; - type T3 is range 1 .. 10; - -- explicit - function "+"(Left : T1; Right : T2) return T3; - end P; - - with P; - procedure UseType is - X1 : P.T1; - X2 : P.T2; - X3 : P.T3; - use type P.T1; - begin - X3 := X1 + X2; -- operator visible because it uses T1 - X2 := X2 + X2; -- operator not visible - end UseType; - -=================== -Renaming Entities -=================== - ---------------------------------- -Three Positives Make a Negative ---------------------------------- - -* Good Coding Practices ... - - - Descriptive names - - Modularization - - Subsystem hierarchies - -* Can result in cumbersome references - - .. code:: Ada - - -- use cosine rule to determine distance between two points, - -- given angle and distances between observer and 2 points - -- A**2 = B**2 + C**2 - 2*B*C*cos(angle) - Observation.Sides (Viewpoint_Types.Point1_Point2) := - Math_Utilities.Square_Root - (Observation.Sides (Viewpoint_Types.Observer_Point1)**2 + - Observation.Sides (Viewpoint_Types.Observer_Point2)**2 - - 2.0 * Observation.Sides (Viewpoint_Types.Observer_Point1) * - Observation.Sides (Viewpoint_Types.Observer_Point2) * - Math_Utilities.Trigonometry.Cosine - (Observation.Vertices (Viewpoint_Types.Observer))); - --------------------------------- -Writing Readable Code - Part 1 --------------------------------- - -* We could use :ada:`use` on package names to remove some dot-notation - - .. code:: Ada - - -- use cosine rule to determine distance between two points, given angle - -- and distances between observer and 2 points A**2 = B**2 + C**2 - - -- 2*B*C*cos(angle) - Observation.Sides (Point1_Point2) := - Square_Root - (Observation.Sides (Observer_Point1)**2 + - Observation.Sides (Observer_Point2)**2 - - 2.0 * Observation.Sides (Observer_Point1) * - Observation.Sides (Observer_Point2) * - Cosine (Observation.Vertices (Observer))); - -* But that only shortens the problem, not simplifies it - - - If there are multiple "use" clauses in scope: - - + Reviewer may have hard time finding the correct definition - + Homographs may cause ambiguous reference errors - -* We want the ability to refer to certain entities by another name (like an alias) with full read/write access (unlike temporary variables) - ------------------------ -The "renames" Keyword ------------------------ - -* :ada:`renames` declaration creates an alias to an entity - - - Packages - - .. code:: Ada - - package Trig renames Math.Trigonometry - - - Objects (or elements of objects) - - .. code:: Ada - - Angles : Viewpoint_Types.Vertices_Array_T - renames Observation.Vertices; - Required_Angle : Viewpoint_Types.Vertices_T - renames Viewpoint_Types.Observer; - - - Subprograms - - .. code:: Ada - - function Sqrt (X : Base_Types.Float_T) - return Base_Types.Float_T - renames Math.Square_Root; - --------------------------------- -Writing Readable Code - Part 2 --------------------------------- - -* With :ada:`renames` our complicated code example is easier to understand - - - Executable code is very close to the specification - - Declarations as "glue" to the implementation details - - .. code:: Ada - - begin - package Math renames Math_Utilities; - package Trig renames Math.Trigonometry; - - function Sqrt (X : Base_Types.Float_T) return Base_Types.Float_T - renames Math.Square_Root; - function Cos ... - - B : Base_Types.Float_T - renames Observation.Sides (Viewpoint_Types.Observer_Point1); - -- Rename the others as Side2, Angles, Required_Angle, Desired_Side - begin - ... - -- A**2 = B**2 + C**2 - 2*B*C*cos(angle) - A := Sqrt (B**2 + C**2 - 2.0 * B * C * Cos (Angle)); - end; - -======== -Lab -======== - -.. include:: labs/135_visibility.lab.rst - -========= -Summary -========= - ---------- -Summary ---------- - -* :ada:`use` clauses are not evil but can be abused - - - Can make it difficult for others to understand code - -* :ada:`use all type` clauses are more likely in practice than :ada:`use type` clauses - -* :ada:`Renames` allow us to alias entities to make code easier to read - - - Subprogram renaming has many other uses, such as adding / removing default parameter values +************ +Visibility +************ + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 135_visibility/01-introduction.rst +.. include:: 135_visibility/02-use_clauses.rst +.. include:: 135_visibility/03-use_type_and_use_all_type_clauses.rst +.. include:: 135_visibility/04-renaming_entities.rst +.. include:: labs/135_visibility.lab.rst +.. include:: 135_visibility/99-summary.rst diff --git a/courses/fundamentals_of_ada/135_visibility/01-introduction.rst b/courses/fundamentals_of_ada/135_visibility/01-introduction.rst new file mode 100644 index 000000000..2c073b7f1 --- /dev/null +++ b/courses/fundamentals_of_ada/135_visibility/01-introduction.rst @@ -0,0 +1,41 @@ +============== +Introduction +============== + +----------------------- +Improving Readability +----------------------- + +* Descriptive names plus hierarchical packages makes for very long statements + + .. code:: + + Messages.Queue.Diagnostics.Inject_Fault ( + Fault => Messages.Queue.Diagnostics.CRC_Failure, + Position => Messages.Queue.Front); + +* Operators treated as functions defeat the purpose of overloading + + .. code:: + + Complex1 := Complex_Types."+" (Complex2, Complex3); + +* Ada has mechanisms to simplify hierarchies + +-------------------------- +Operators and Primitives +-------------------------- + +* :dfn:`Operators` + + - Constructs which behave generally like functions but which differ syntactically or semantically + - Typically arithmetic, comparison, and logical + +* **Primitive operation** + + - Predefined operations such as ``=`` and ``+`` etc. + - Subprograms declared in the same package as the type and which operate on the type + - Inherited or overridden subprograms + - For :ada:`tagged` types, class-wide subprograms + - Enumeration literals + diff --git a/courses/fundamentals_of_ada/135_visibility/02-use_clauses.rst b/courses/fundamentals_of_ada/135_visibility/02-use_clauses.rst new file mode 100644 index 000000000..3ea3f77d5 --- /dev/null +++ b/courses/fundamentals_of_ada/135_visibility/02-use_clauses.rst @@ -0,0 +1,198 @@ +=============== +"use" Clauses +=============== + +--------------- +"use" Clauses +--------------- + +* :ada:`use Pkg;` provides direct visibility into public items in :ada:`Pkg` + + + :dfn:`Direct Visibility` - as if object was referenced from within package being used + + :dfn:`Public Items` - any entity defined in package spec public section + +* May still use expanded name + +.. code:: Ada + + package Ada.Text_IO is + procedure Put_Line (...); + procedure New_Line (...); + ... + end Ada.Text_IO; + + with Ada.Text_IO; + procedure Hello is + use Ada.Text_IO; + begin + Put_Line ("Hello World"); + New_Line (3); + Ada.Text_IO.Put_Line ("Good bye"); + end Hello; + +--------------------- +"use" Clause Syntax +--------------------- + +* May have several, like :ada:`with` clauses +* Can refer to any visible package (including nested packages) +* Syntax + + .. code:: Ada + + use_package_clause ::= use package_name {, package_name}; + +* Can only :ada:`use` a package + + - Subprograms have no contents to :ada:`use` + +-------------------- +"use" Clause Scope +-------------------- + +* Applies to end of body, from first occurrence + +.. code:: Ada + + package Pkg_A is + Constant_A : constant := 123; + end Pkg_A; + + package Pkg_B is + Constant_B : constant := 987; + end Pkg_B; + + with Pkg_A; + with Pkg_B; + use Pkg_A; -- everything in Pkg_A is now visible + package P is + A : Integer := Constant_A; -- legal + B1 : Integer := Constant_B; -- illegal + use Pkg_B; -- everything in Pkg_B is now visible + B2 : Integer := Constant_B; -- legal + function F return Integer; + end P; + + package body P is + -- all of Pkg_A and Pkg_B is visible here + function F return Integer is (Constant_A + Constant_B); + end P; + +-------------------- +No Meaning Changes +-------------------- + +* A new :ada:`use` clause won't change a program's meaning! +* Any directly visible names still refer to the original entities + +.. code:: Ada + + package D is + T : Float; + end D; + + with D; + procedure P is + procedure Q is + T, X : Float; + begin + ... + declare + use D; + begin + -- With or without the clause, "T" means Q.T + X := T; + end; + ... + end Q; + +--------------------------- +No Ambiguity Introduction +--------------------------- + +.. code:: Ada + + package D is + V : Boolean; + end D; + + package E is + V : Integer; + end E; + with D, E; + + procedure P is + procedure Q is + use D, E; + begin + -- to use V here, must specify D.V or E.V + ... + end Q; + begin + ... + +.. container:: speakernote + + For declarations in different packages that would not be directly visible in the absence of a "use" clause, none with the same identifier will be directly visible in the presence of such a clause, unless both are overloadable (i.e., enumeration literals and subprogram declarations) + +------------------------------ +"use" Clauses and Child Units +------------------------------ + +* A clause for a child does **not** imply one for its parent +* A clause for a parent makes the child **directly** visible + + - Since children are 'inside' declarative region of parent + +.. code:: Ada + + package Parent is + P1 : Integer; + end Parent; + + package Parent.Child is + PC1 : Integer; + end Parent.Child; + + with Parent; + with Parent.Child; use Parent.Child; + procedure Demo is + D1 : Integer := Parent.P1; + D2 : Integer := Parent.Child.PC1; + use Parent; + D3 : Integer := P1; -- illegal + D4 : Integer := PC1; + ... + +.. container:: speakernote + + D4 has access to CHILD because PARENT is "use"d + +---------------------------------------- +"use" Clause and Implicit Declarations +---------------------------------------- + +* Visibility rules apply to implicit declarations too + +.. code:: Ada + + package P is + type Int is range Lower .. Upper; + -- implicit declarations + -- function "+"(Left, Right : Int) return Int; + -- function "="(Left, Right : Int) return Boolean; + end P; + + with P; + procedure Test is + A, B, C : P.Int := some_value; + begin + C := A + B; -- illegal reference to operator + C := P."+" (A,B); + declare + use P; + begin + C := A + B; -- now legal + end; + end Test; + diff --git a/courses/fundamentals_of_ada/135_visibility/03-use_type_and_use_all_type_clauses.rst b/courses/fundamentals_of_ada/135_visibility/03-use_type_and_use_all_type_clauses.rst new file mode 100644 index 000000000..f37a35389 --- /dev/null +++ b/courses/fundamentals_of_ada/135_visibility/03-use_type_and_use_all_type_clauses.rst @@ -0,0 +1,89 @@ +======================================= +"use type" and "use all type" Clauses +======================================= + +------------------------------- +"use type" and "use all type" +------------------------------- + +* :ada:`use type` makes **primitive operators** directly visible for specified type + + - Implicit and explicit operator function declarations + + .. code:: Ada + + use type subtype_mark {, subtype_mark}; + +* :ada:`use all type` makes primitive operators **and all other operations** directly visible for specified type + + - All **enumerated type values** will also be directly visible + + .. code:: Ada + + use all type subtype_mark {, subtype_mark}; + +* More specific alternatives to :ada:`use` clauses + + - Especially useful when multiple :ada:`use` clauses introduce ambiguity + +-------------- +Example Code +-------------- + +.. code:: Ada + + package Types is + type Distance_T is range 0 .. Integer'Last; + + -- explicit declaration + -- (we don't want a negative distance) + function "-" (Left, Right : Distance_T) + return Distance_T; + + -- implicit declarations (we get the division operator + -- for "free", showing it for completeness) + -- function "/" (Left, Right : Distance_T) return + -- Distance_T; + + -- primitive operation + function Min (A, B : Distance_T) + return Distance_T; + + end Types; + +-------------------------- +"use" Clauses Comparison +-------------------------- + +.. image:: use_clause_comparison.png + +----------------------------- +Multiple "use type" Clauses +----------------------------- + +* May be necessary +* Only those that mention the type in their profile are made visible + +.. code:: Ada + + package P is + type T1 is range 1 .. 10; + type T2 is range 1 .. 10; + -- implicit + -- function "+"(Left : T2; Right : T2) return T2; + type T3 is range 1 .. 10; + -- explicit + function "+"(Left : T1; Right : T2) return T3; + end P; + + with P; + procedure UseType is + X1 : P.T1; + X2 : P.T2; + X3 : P.T3; + use type P.T1; + begin + X3 := X1 + X2; -- operator visible because it uses T1 + X2 := X2 + X2; -- operator not visible + end UseType; + diff --git a/courses/fundamentals_of_ada/135_visibility/04-renaming_entities.rst b/courses/fundamentals_of_ada/135_visibility/04-renaming_entities.rst new file mode 100644 index 000000000..82ced9ed1 --- /dev/null +++ b/courses/fundamentals_of_ada/135_visibility/04-renaming_entities.rst @@ -0,0 +1,115 @@ +=================== +Renaming Entities +=================== + +--------------------------------- +Three Positives Make a Negative +--------------------------------- + +* Good Coding Practices ... + + - Descriptive names + - Modularization + - Subsystem hierarchies + +* Can result in cumbersome references + + .. code:: Ada + + -- use cosine rule to determine distance between two points, + -- given angle and distances between observer and 2 points + -- A**2 = B**2 + C**2 - 2*B*C*cos(angle) + Observation.Sides (Viewpoint_Types.Point1_Point2) := + Math_Utilities.Square_Root + (Observation.Sides (Viewpoint_Types.Observer_Point1)**2 + + Observation.Sides (Viewpoint_Types.Observer_Point2)**2 - + 2.0 * Observation.Sides (Viewpoint_Types.Observer_Point1) * + Observation.Sides (Viewpoint_Types.Observer_Point2) * + Math_Utilities.Trigonometry.Cosine + (Observation.Vertices (Viewpoint_Types.Observer))); + +-------------------------------- +Writing Readable Code - Part 1 +-------------------------------- + +* We could use :ada:`use` on package names to remove some dot-notation + + .. code:: Ada + + -- use cosine rule to determine distance between two points, given angle + -- and distances between observer and 2 points A**2 = B**2 + C**2 - + -- 2*B*C*cos(angle) + Observation.Sides (Point1_Point2) := + Square_Root + (Observation.Sides (Observer_Point1)**2 + + Observation.Sides (Observer_Point2)**2 - + 2.0 * Observation.Sides (Observer_Point1) * + Observation.Sides (Observer_Point2) * + Cosine (Observation.Vertices (Observer))); + +* But that only shortens the problem, not simplifies it + + - If there are multiple "use" clauses in scope: + + + Reviewer may have hard time finding the correct definition + + Homographs may cause ambiguous reference errors + +* We want the ability to refer to certain entities by another name (like an alias) with full read/write access (unlike temporary variables) + +----------------------- +The "renames" Keyword +----------------------- + +* :ada:`renames` declaration creates an alias to an entity + + - Packages + + .. code:: Ada + + package Trig renames Math.Trigonometry + + - Objects (or elements of objects) + + .. code:: Ada + + Angles : Viewpoint_Types.Vertices_Array_T + renames Observation.Vertices; + Required_Angle : Viewpoint_Types.Vertices_T + renames Viewpoint_Types.Observer; + + - Subprograms + + .. code:: Ada + + function Sqrt (X : Base_Types.Float_T) + return Base_Types.Float_T + renames Math.Square_Root; + +-------------------------------- +Writing Readable Code - Part 2 +-------------------------------- + +* With :ada:`renames` our complicated code example is easier to understand + + - Executable code is very close to the specification + - Declarations as "glue" to the implementation details + + .. code:: Ada + + begin + package Math renames Math_Utilities; + package Trig renames Math.Trigonometry; + + function Sqrt (X : Base_Types.Float_T) return Base_Types.Float_T + renames Math.Square_Root; + function Cos ... + + B : Base_Types.Float_T + renames Observation.Sides (Viewpoint_Types.Observer_Point1); + -- Rename the others as Side2, Angles, Required_Angle, Desired_Side + begin + ... + -- A**2 = B**2 + C**2 - 2*B*C*cos(angle) + A := Sqrt (B**2 + C**2 - 2.0 * B * C * Cos (Angle)); + end; + diff --git a/courses/fundamentals_of_ada/135_visibility/05-lab.rst b/courses/fundamentals_of_ada/135_visibility/05-lab.rst new file mode 100644 index 000000000..ffae43cb1 --- /dev/null +++ b/courses/fundamentals_of_ada/135_visibility/05-lab.rst @@ -0,0 +1,45 @@ +======== +Lab +======== + +---------------- +Visibility Lab +---------------- + +* Requirements + + - Create two types packages for two different shapes. Each package should have the following components: + + + :ada:`Number_of_Sides` - indicates how many sides in the shape + + :ada:`Side_T` - numeric value for length + + :ada:`Shape_T` - array of :ada:`Side_T` elements whose length is :ada:`Number_of_Sides` + + - Create a main program that will + + + Create an object of each :ada:`Shape_T` + + Set the values for each element in :ada:`Shape_T` + + Add all the elements in each object and print the total + +* Hints + + - There are multiple ways to resolve this! + +---------------------------------------- +Visibility Lab Solution - Types +---------------------------------------- + +.. container:: source_include labs/answers/135_visibility.txt :start-after:--Types :end-before:--Types :code:Ada :number-lines:1 + +----------------------------------- +Visibility Lab Solution - Main #1 +----------------------------------- + +.. container:: source_include labs/answers/135_visibility.txt :start-after:--Main1 :end-before:--Main1 :code:Ada :number-lines:1 + +----------------------------------- +Visibility Lab Solution - Main #2 +----------------------------------- + +.. container:: source_include labs/answers/135_visibility.txt :start-after:--Main2 :end-before:--Main2 :code:Ada :number-lines:1 +.. include:: labs/135_visibility.lab.rst + diff --git a/courses/fundamentals_of_ada/135_visibility/99-summary.rst b/courses/fundamentals_of_ada/135_visibility/99-summary.rst new file mode 100644 index 000000000..ebc19afb1 --- /dev/null +++ b/courses/fundamentals_of_ada/135_visibility/99-summary.rst @@ -0,0 +1,17 @@ +========= +Summary +========= + +--------- +Summary +--------- + +* :ada:`use` clauses are not evil but can be abused + + - Can make it difficult for others to understand code + +* :ada:`use all type` clauses are more likely in practice than :ada:`use type` clauses + +* :ada:`Renames` allow us to alias entities to make code easier to read + + - Subprogram renaming has many other uses, such as adding / removing default parameter values diff --git a/courses/fundamentals_of_ada/labs/135_visibility.lab.rst b/courses/fundamentals_of_ada/labs/135_visibility.lab.rst index db589bfb9..597000e4a 100644 --- a/courses/fundamentals_of_ada/labs/135_visibility.lab.rst +++ b/courses/fundamentals_of_ada/labs/135_visibility.lab.rst @@ -1,3 +1,7 @@ +======== +Lab +======== + ---------------- Visibility Lab ---------------- From 26d856de6503f2888c415080f76c836e96564a2a Mon Sep 17 00:00:00 2001 From: Michael Frank Date: Wed, 11 Dec 2024 14:27:45 +0000 Subject: [PATCH 11/11] Resolve "Break 170_tagged_derivation into chapters" --- .../170_tagged_derivation-intro.rst | 40 ++ .../170_tagged_derivation.rst | 555 ++--------------- .../170_tagged_derivation/01-introduction.rst | 65 ++ .../02-tagged_derivation-simple.rst | 233 ++++++++ .../02-tagged_derivation.rst | 188 ++++++ .../03-extending_tagged_types.rst | 204 +++++++ .../170_tagged_derivation/99-summary.rst | 17 + .../175_multiple_inheritance.rst | 39 ++ .../01-introduction.rst | 58 ++ .../02-interfaces.rst | 88 +++ .../175_multiple_inheritance/99-summary.rst | 18 + .../adv_170_multiple_inheritance.rst | 205 ------- courses/fundamentals_of_ada/advanced.txt | 2 +- .../intro_170_tagged_derivation.rst | 564 ------------------ ...t => 170_tagged_derivation-simple.lab.rst} | 10 +- .../labs/170_tagged_derivation.lab.rst | 4 + ...b.rst => 175_multiple_inheritance.lab.rst} | 18 +- ...n.txt => 170_tagged_derivation-simple.txt} | 0 ...tance.txt => 175_multiple_inheritance.txt} | 0 .../base_types.ads | 0 .../default.gpr | 0 .../geometry.ads | 0 .../line_draw.adb | 0 .../line_draw.ads | 0 .../main.adb | 0 .../printable_object.adb | 0 .../printable_object.ads | 0 .../rectangle.adb | 0 .../rectangle.ads | 0 courses/fundamentals_of_ada/opat.txt | 2 +- .../fundamentals_of_ada/standard_course.txt | 2 +- 31 files changed, 1015 insertions(+), 1297 deletions(-) create mode 100644 courses/fundamentals_of_ada/170_tagged_derivation-intro.rst create mode 100644 courses/fundamentals_of_ada/170_tagged_derivation/01-introduction.rst create mode 100644 courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation-simple.rst create mode 100644 courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation.rst create mode 100644 courses/fundamentals_of_ada/170_tagged_derivation/03-extending_tagged_types.rst create mode 100644 courses/fundamentals_of_ada/170_tagged_derivation/99-summary.rst create mode 100644 courses/fundamentals_of_ada/175_multiple_inheritance.rst create mode 100644 courses/fundamentals_of_ada/175_multiple_inheritance/01-introduction.rst create mode 100644 courses/fundamentals_of_ada/175_multiple_inheritance/02-interfaces.rst create mode 100644 courses/fundamentals_of_ada/175_multiple_inheritance/99-summary.rst delete mode 100644 courses/fundamentals_of_ada/adv_170_multiple_inheritance.rst delete mode 100644 courses/fundamentals_of_ada/intro_170_tagged_derivation.rst rename courses/fundamentals_of_ada/labs/{intro_170_tagged_derivation.lab.rst => 170_tagged_derivation-simple.lab.rst} (68%) rename courses/fundamentals_of_ada/labs/{adv_170_multiple_inheritance.lab.rst => 175_multiple_inheritance.lab.rst} (61%) rename courses/fundamentals_of_ada/labs/answers/{intro_170_tagged_derivation.txt => 170_tagged_derivation-simple.txt} (100%) rename courses/fundamentals_of_ada/labs/answers/{adv_170_multiple_inheritance.txt => 175_multiple_inheritance.txt} (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/base_types.ads (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/default.gpr (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/geometry.ads (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/line_draw.adb (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/line_draw.ads (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/main.adb (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/printable_object.adb (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/printable_object.ads (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/rectangle.adb (100%) rename courses/fundamentals_of_ada/labs/prompts/{adv_170_multiple_inheritance => 175_multiple_inheritance}/rectangle.ads (100%) diff --git a/courses/fundamentals_of_ada/170_tagged_derivation-intro.rst b/courses/fundamentals_of_ada/170_tagged_derivation-intro.rst new file mode 100644 index 000000000..3a09053be --- /dev/null +++ b/courses/fundamentals_of_ada/170_tagged_derivation-intro.rst @@ -0,0 +1,40 @@ +***************** +Tagged Derivation +***************** + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 170_tagged_derivation/01-introduction.rst +.. include:: 170_tagged_derivation/02-tagged_derivation-simple.rst +.. include:: labs/170_tagged_derivation-simple.lab.rst +.. include:: 170_tagged_derivation/99-summary.rst +.. include:: 170_tagged_derivation/03-extending_tagged_types.rst diff --git a/courses/fundamentals_of_ada/170_tagged_derivation.rst b/courses/fundamentals_of_ada/170_tagged_derivation.rst index a11e4a028..2d2c8d426 100644 --- a/courses/fundamentals_of_ada/170_tagged_derivation.rst +++ b/courses/fundamentals_of_ada/170_tagged_derivation.rst @@ -1,515 +1,40 @@ -***************** -Tagged Derivation -***************** - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - ---------------------------------------------- -Object-Oriented Programming with Tagged Types ---------------------------------------------- - -* For :ada:`record` types - - .. code:: Ada - - type T is tagged record - ... - -* Child types can add new components (*attributes*) -* Object of a child type can be **substituted** for base type -* Primitive (*method*) can :dfn:`dispatch` **at run-time** depending on the type at call-site -* Types can be **extended** by other packages - - - Conversion and qualification to base type is allowed - -* Private data is encapsulated through **privacy** - ------------------------------- -Tagged Derivation Ada Vs C++ ------------------------------- - -.. container:: columns - - .. container:: column - - .. code:: Ada - - type T1 is tagged record - Member1 : Integer; - end record; - - procedure Attr_F (This : T1); - - type T2 is new T1 with record - Member2 : Integer; - end record; - - overriding procedure Attr_F ( - This : T2); - procedure Attr_F2 (This : T2); - - .. container:: column - - .. code:: C++ - - class T1 { - public: - int Member1; - virtual void Attr_F(void); - }; - - class T2 : public T1 { - public: - int Member2; - virtual void Attr_F(void); - virtual void Attr_F2(void); - }; - -================= -Tagged Derivation -================= - ---------------------------------- -Difference with Simple Derivation ---------------------------------- - -* Tagged derivation **can** change the structure of a type - - - Keywords :ada:`tagged record` and :ada:`with record` - - .. code:: Ada - - type Root is tagged record - F1 : Integer; - end record; - - type Child is new Root with record - F2 : Integer; - end record; - -* Conversion is only allowed from **child to parent** - - .. code:: Ada - - V1 : Root; - V2 : Child; - ... - V1 := Root (V2); - V2 := Child (V1); -- illegal - ------------- -Primitives ------------- - -* Child **cannot remove** a primitive -* Child **can add** new primitives -* :dfn:`Controlling parameter` - - - Parameters the subprogram is a primitive of - - For :ada:`tagged` types, all should have the **same type** - - .. code:: Ada - - type Root1 is tagged null record; - type Root2 is tagged null record; - - procedure P1 (V1 : Root1; - V2 : Root1); - procedure P2 (V1 : Root1; - V2 : Root2); -- illegal - -------------------------------- -Freeze Point for Tagged Types -------------------------------- - -* Freeze point definition does not change - - - A variable of the type is declared - - The type is derived - - The end of the scope is reached - -* Declaring tagged type primitives past freeze point is **forbidden** - -.. code:: Ada - - type Root is tagged null record; - - procedure Prim (V : Root); - - type Child is new Root with null record; -- freeze root - - procedure Prim2 (V : Root); -- illegal - - V : Child; -- freeze child - - procedure Prim3 (V : Child); -- illegal - ---------------------- -Overriding Indicators ---------------------- - -* Optional :ada:`overriding` and :ada:`not overriding` indicators - - .. code:: Ada - - type Shape_T is tagged record - Name : String (1..10); - end record; - - -- primitives of "Shape_T" - function Get_Name (S : Shape_T) return String; - procedure Set_Name (S : in out Shape_T); - - -- Derive "Point" from Shape_T - type Point_T is new Shape_T with record - Origin : Coord_T; - end Point_T; - - -- Get_Name is inherited - -- We want to _change_ the behavior of Set_Name - overriding procedure Set_Name (P : in out Point_T); - -- We want to _add_ a new primitive - not overriding procedure Set_Origin (P : in out Point_T); - -.. - language_version 2005 - ------------------ -Prefix Notation ------------------ - -* Tagged types primitives can be called as usual -* The call can use prefixed notation - - - **If** the first argument is a controlling parameter - - No need for :ada:`use` or :ada:`use type` for visibility - - .. code:: Ada - - -- Prim1 visible even without *use Pkg* - X.Prim1; - - declare - use Pkg; - begin - Prim1 (X); - end; - -.. - language_version 2005 - ------- -Quiz ------- - -.. include:: quiz/tagged_primitives/quiz.rst - ------- -Quiz ------- - -.. include:: quiz/tagged_dot_and_with/quiz.rst - ------- -Quiz ------- - -Which code block(s) is (are) legal? - -.. container:: columns - - .. container:: column - - A. | ``type A1 is record`` - | ``Field1 : Integer;`` - | ``end record;`` - | ``type A2 is new A1 with null record;`` - B. | :answermono:`type B1 is tagged record` - | :answermono:`Field2 : Integer;` - | :answermono:`end record;` - | :answermono:`type B2 is new B1 with record` - | :answermono:`Field2b : Integer;` - | :answermono:`end record;` - - .. container:: column - - C. | ``type C1 is tagged record`` - | ``Field3 : Integer;`` - | ``end record;`` - | ``type C2 is new C1 with record`` - | ``Field3 : Integer;`` - | ``end record;`` - D. | ``type D1 is tagged record`` - | ``Field1 : Integer;`` - | ``end record;`` - | ``type D2 is new D1;`` - -.. container:: animate - - Explanations - - A. Cannot extend a non-tagged type - B. Correct - C. Components must have distinct names - D. Types derived from a tagged type must have an extension - -======================== -Extending Tagged Types -======================== - ----------------------------------- -How Do You Extend a Tagged Type? ----------------------------------- - -* Premise of a tagged type is to :dfn:`extend` an existing type - -* In general, that means we want to add more fields - - * We can extend a :ada:`tagged` type by adding fields - - .. code:: Ada - - package Animals is - type Animal_T is tagged record - Age : Natural; - end record; - end Animals; - - with Animals; use Animals; - package Mammals is - type Mammal_T is new Animal_T with record - Number_Of_Legs : Natural; - end record; - end Mammals; - - with Mammals; use Mammals; - package Canines is - type Canine_T is new Mammal_T with record - Domesticated : Boolean; - end record; - end Canines; - ------------------- -Tagged Aggregate ------------------- - -* At initialization, all fields (including **inherited**) must have a **value** - - .. code:: Ada - - Animal : Animal_T := (Age => 1); - Mammal : Mammal_T := (Age => 2, - Number_Of_Legs => 2); - Canine : Canine_T := (Age => 2, - Number_Of_Legs => 4, - Domesticated => True); - -* But we can also "seed" the aggregate with a parent object - - .. code:: Ada - - Mammal := (Animal with Number_Of_Legs => 4); - Canine := (Animal with Number_Of_Legs => 4, - Domesticated => False); - Canine := (Mammal with Domesticated => True); - ----------------------- -Private Tagged Types ----------------------- - -* But data hiding says types should be private! - -* So we can define our base type as private - - .. container:: latex_environment tiny - - .. code:: Ada - - package Animals is - type Animal_T is tagged private; - function Get_Age (P : Animal_T) return Natural; - procedure Set_Age (P : in out Animal_T; A : Natural); - private - type Animal_T is tagged record - Age : Natural; - end record; - end Animals; - -* And still allow derivation - - .. container:: latex_environment tiny - - .. code:: Ada - - with Animals; - package Mammals is - type Mammal_T is new Animals.Animal_T with record - Number_Of_Legs : Natural; - end record; - -* But now the only way to get access to :ada:`Age` is with accessor subprograms - --------------------- -Private Extensions --------------------- - -* In the previous slide, we exposed the fields for :ada:`Mammal_T`! - -* Better would be to make the extension itself private - - .. code:: Ada - - package Mammals is - type Mammal_T is new Animals.Animal_T with private; - private - type Mammal_T is new Animals.Animal_T with record - Number_Of_Legs : Natural; - end record; - end Mammals; - --------------------------------------- -Aggregates with Private Tagged Types --------------------------------------- - -* Remember, an aggregate must specify values for all components - - * But with private types, we can't see all the components! - -* So we need to use the "seed" method: - - .. code:: Ada - - procedure Inside_Mammals_Pkg is - Animal : Animal_T := Animals.Create; - Mammal : Mammal_T; - begin - Mammal := (Animal with Number_Of_Legs => 4); - Mammal := (Animals.Create with Number_Of_Legs => 4); - end Inside_Mammals_Pkg; - -* Note that we cannot use :ada:`others => <>` for components that are not visible to us - - .. code:: Ada - - Mammal := (Number_Of_Legs => 4, - others => <>); -- Compile Error - ------------------ -Null Extensions ------------------ - -* To create a new type with no additional fields - - * We still need to "extend" the record - we just do it with an empty record - - .. code:: Ada - - type Dog_T is new Canine_T with null record; - - -* We still need to specify the "added" fields in an aggregate - - .. code:: Ada - - C : Canine_T := Canines.Create; - Dog1 : Dog_T := C; -- Compile Error - Dog2 : Dog_T := (C with null record); - ------- -Quiz ------- - -Given the following code: - - .. code::ada - - package Parents is - type Parent_T is tagged private; - function Create return Parent_T; - private - type Parent_T is tagged record - Id : Integer; - end record; - end Parents; - - with Parents; use Parents; - package Children is - P : Parent_T; - type Child_T is new Parent_T with record - Count : Natural; - end record; - function Create (C : Natural) return Child_T; - end Children; - -Which completion(s) of Create is (are) valid? - - A. :answermono:`function Create return Child_T is (Parents.Create with Count => 0);` - B. ``function Create return Child_T is (others => <>);`` - B. ``function Create return Child_T is (0, 0);`` - D. :answermono:`function Create return Child_T is (P with Count => 0);` - -.. container:: animate - - Explanations - - A. Correct - :ada:`Parents.Create` returns :ada:`Parent_T` - B. Cannot use :ada:`others` to complete private part of an aggregate - C. Aggregate has no visibility to :ada:`Id` field, so cannot assign - D. Correct - :ada:`P` is a :ada:`Parent_T` - -======== -Lab -======== - -.. include:: labs/170_tagged_derivation.lab.rst - -========= -Summary -========= - ---------- -Summary ---------- - -* Tagged derivation - - - Building block for OOP types in Ada - -* Primitives rules for tagged types are trickier - - - Primitives **forbidden** below freeze point - - **Unique** controlling parameter - - Tip: Keep the number of tagged type per package low +***************** +Tagged Derivation +***************** + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 170_tagged_derivation/01-introduction.rst +.. include:: 170_tagged_derivation/02-tagged_derivation.rst +.. include:: 170_tagged_derivation/03-extending_tagged_types.rst +.. include:: labs/170_tagged_derivation.lab.rst +.. include:: 170_tagged_derivation/99-summary.rst diff --git a/courses/fundamentals_of_ada/170_tagged_derivation/01-introduction.rst b/courses/fundamentals_of_ada/170_tagged_derivation/01-introduction.rst new file mode 100644 index 000000000..6b6ad791c --- /dev/null +++ b/courses/fundamentals_of_ada/170_tagged_derivation/01-introduction.rst @@ -0,0 +1,65 @@ +============== +Introduction +============== + +--------------------------------------------- +Object-Oriented Programming with Tagged Types +--------------------------------------------- + +* For :ada:`record` types + + .. code:: Ada + + type T is tagged record + ... + +* Child types can add new components (*attributes*) +* Object of a child type can be **substituted** for base type +* Primitive (*method*) can :dfn:`dispatch` **at run-time** depending on the type at call-site +* Types can be **extended** by other packages + + - Conversion and qualification to base type is allowed + +* Private data is encapsulated through **privacy** + +------------------------------ +Tagged Derivation Ada Vs C++ +------------------------------ + +.. container:: columns + + .. container:: column + + .. code:: Ada + + type T1 is tagged record + Member1 : Integer; + end record; + + procedure Attr_F (This : T1); + + type T2 is new T1 with record + Member2 : Integer; + end record; + + overriding procedure Attr_F ( + This : T2); + procedure Attr_F2 (This : T2); + + .. container:: column + + .. code:: C++ + + class T1 { + public: + int Member1; + virtual void Attr_F(void); + }; + + class T2 : public T1 { + public: + int Member2; + virtual void Attr_F(void); + virtual void Attr_F2(void); + }; + diff --git a/courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation-simple.rst b/courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation-simple.rst new file mode 100644 index 000000000..348cdb728 --- /dev/null +++ b/courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation-simple.rst @@ -0,0 +1,233 @@ +================= +Tagged Derivation +================= + +--------------------------------- +Difference with Simple Derivation +--------------------------------- + +* Tagged derivation **can** change the structure of a type + + - Keywords :ada:`tagged record` and :ada:`with record` + + .. code:: Ada + + type Root is tagged record + F1 : Integer; + end record; + + type Child is new Root with record + F2 : Integer; + end record; + +-------------- +Type Extension +-------------- + +* A tagged derivation **has** to be a type extension + + - Use :ada:`with null record` if there are no additional components + + .. code:: Ada + + type Child is new Root with null record; + type Child is new Root; -- illegal + +* Conversion is only allowed from **child to parent** + + .. code:: Ada + + V1 : Root; + V2 : Child; + ... + V1 := Root (V2); + V2 := Child (V1); -- illegal + +*Information on extending private types appears at the end of this module* + +------------ +Primitives +------------ + +* Child **cannot remove** a primitive +* Child **can add** new primitives +* :dfn:`Controlling parameter` + + - Parameters the subprogram is a primitive of + - For :ada:`tagged` types, all should have the **same type** + + .. code:: Ada + + type Root1 is tagged null record; + type Root2 is tagged null record; + + procedure P1 (V1 : Root1; + V2 : Root1); + procedure P2 (V1 : Root1; + V2 : Root2); -- illegal + +------------------------------- +Freeze Point for Tagged Types +------------------------------- + +* Freeze point definition does not change + + - A variable of the type is declared + - The type is derived + - The end of the scope is reached + +* Declaring tagged type primitives past freeze point is **forbidden** + +.. code:: Ada + + type Root is tagged null record; + + procedure Prim (V : Root); + + type Child is new Root with null record; -- freeze root + + procedure Prim2 (V : Root); -- illegal + + V : Child; -- freeze child + + procedure Prim3 (V : Child); -- illegal + +------------------ +Tagged Aggregate +------------------ + +* At initialization, all fields (including **inherited**) must have a **value** + + .. code:: Ada + + type Root is tagged record + F1 : Integer; + end record; + + type Child is new Root with record + F2 : Integer; + end record; + + V : Child := (F1 => 0, F2 => 0); + +* For **private types** use :dfn:`aggregate extension` + + - Copy of a parent instance + - Use :ada:`with null record` absent new fields + + .. code:: Ada + + V2 : Child := (Parent_Instance with F2 => 0); + V3 : Empty_Child := (Parent_Instance with null record); + +*Information on aggregates of private extensions appears at the end of this module* + +--------------------- +Overriding Indicators +--------------------- + +* Optional :ada:`overriding` and :ada:`not overriding` indicators + + .. code:: Ada + + type Shape_T is tagged record + Name : String (1..10); + end record; + + -- primitives of "Shape_T" + procedure Set_Name (S : in out Shape_T); + function Name (S : Shape_T) return String; + + -- Derive "Point" from Shape_T + type Point is new Shape_T with record + Origin : Coord_T; + end Point; + + -- We want to _change_ the behavior of Set_Name + overriding procedure Set_Name (P : in out Point_T); + -- We want to _add_ a new primitive + not overriding Origin (P : Point_T) return Point_T; + -- We get "Name" for free + +.. + language_version 2005 + +----------------- +Prefix Notation +----------------- + +* Tagged types primitives can be called as usual +* The call can use prefixed notation + + - **If** the first argument is a controlling parameter + - No need for :ada:`use` or :ada:`use type` for visibility + + .. code:: Ada + + -- Prim1 visible even without *use Pkg* + X.Prim1; + + declare + use Pkg; + begin + Prim1 (X); + end; + +.. + language_version 2012 + +------ +Quiz +------ + +.. include:: ../quiz/tagged_primitives/quiz.rst + +------ +Quiz +------ + +.. include:: ../quiz/tagged_dot_and_with/quiz.rst + +------ +Quiz +------ + +Which code block(s) is (are) legal? + +.. container:: columns + + .. container:: column + + A. | ``type A1 is record`` + | ``Field1 : Integer;`` + | ``end record;`` + | ``type A2 is new A1 with null record;`` + B. | :answermono:`type B1 is tagged record` + | :answermono:`Field2 : Integer;` + | :answermono:`end record;` + | :answermono:`type B2 is new B1 with record` + | :answermono:`Field2b : Integer;` + | :answermono:`end record;` + + .. container:: column + + C. | ``type C1 is tagged record`` + | ``Field3 : Integer;`` + | ``end record;`` + | ``type C2 is new C1 with record`` + | ``Field3 : Integer;`` + | ``end record;`` + D. | ``type D1 is tagged record`` + | ``Field1 : Integer;`` + | ``end record;`` + | ``type D2 is new D1;`` + +.. container:: animate + + Explanations + + A. Cannot extend a non-tagged type + B. Correct + C. Components must have distinct names + D. Types derived from a tagged type must have an extension + diff --git a/courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation.rst b/courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation.rst new file mode 100644 index 000000000..9bc05675f --- /dev/null +++ b/courses/fundamentals_of_ada/170_tagged_derivation/02-tagged_derivation.rst @@ -0,0 +1,188 @@ +================= +Tagged Derivation +================= + +--------------------------------- +Difference with Simple Derivation +--------------------------------- + +* Tagged derivation **can** change the structure of a type + + - Keywords :ada:`tagged record` and :ada:`with record` + + .. code:: Ada + + type Root is tagged record + F1 : Integer; + end record; + + type Child is new Root with record + F2 : Integer; + end record; + +* Conversion is only allowed from **child to parent** + + .. code:: Ada + + V1 : Root; + V2 : Child; + ... + V1 := Root (V2); + V2 := Child (V1); -- illegal + +------------ +Primitives +------------ + +* Child **cannot remove** a primitive +* Child **can add** new primitives +* :dfn:`Controlling parameter` + + - Parameters the subprogram is a primitive of + - For :ada:`tagged` types, all should have the **same type** + + .. code:: Ada + + type Root1 is tagged null record; + type Root2 is tagged null record; + + procedure P1 (V1 : Root1; + V2 : Root1); + procedure P2 (V1 : Root1; + V2 : Root2); -- illegal + +------------------------------- +Freeze Point for Tagged Types +------------------------------- + +* Freeze point definition does not change + + - A variable of the type is declared + - The type is derived + - The end of the scope is reached + +* Declaring tagged type primitives past freeze point is **forbidden** + +.. code:: Ada + + type Root is tagged null record; + + procedure Prim (V : Root); + + type Child is new Root with null record; -- freeze root + + procedure Prim2 (V : Root); -- illegal + + V : Child; -- freeze child + + procedure Prim3 (V : Child); -- illegal + +--------------------- +Overriding Indicators +--------------------- + +* Optional :ada:`overriding` and :ada:`not overriding` indicators + + .. code:: Ada + + type Shape_T is tagged record + Name : String (1..10); + end record; + + -- primitives of "Shape_T" + function Get_Name (S : Shape_T) return String; + procedure Set_Name (S : in out Shape_T); + + -- Derive "Point" from Shape_T + type Point_T is new Shape_T with record + Origin : Coord_T; + end Point_T; + + -- Get_Name is inherited + -- We want to _change_ the behavior of Set_Name + overriding procedure Set_Name (P : in out Point_T); + -- We want to _add_ a new primitive + not overriding procedure Set_Origin (P : in out Point_T); + +.. + language_version 2005 + +----------------- +Prefix Notation +----------------- + +* Tagged types primitives can be called as usual +* The call can use prefixed notation + + - **If** the first argument is a controlling parameter + - No need for :ada:`use` or :ada:`use type` for visibility + + .. code:: Ada + + -- Prim1 visible even without *use Pkg* + X.Prim1; + + declare + use Pkg; + begin + Prim1 (X); + end; + +.. + language_version 2005 + +------ +Quiz +------ + +.. include:: ../quiz/tagged_primitives/quiz.rst + +------ +Quiz +------ + +.. include:: ../quiz/tagged_dot_and_with/quiz.rst + +------ +Quiz +------ + +Which code block(s) is (are) legal? + +.. container:: columns + + .. container:: column + + A. | ``type A1 is record`` + | ``Field1 : Integer;`` + | ``end record;`` + | ``type A2 is new A1 with null record;`` + B. | :answermono:`type B1 is tagged record` + | :answermono:`Field2 : Integer;` + | :answermono:`end record;` + | :answermono:`type B2 is new B1 with record` + | :answermono:`Field2b : Integer;` + | :answermono:`end record;` + + .. container:: column + + C. | ``type C1 is tagged record`` + | ``Field3 : Integer;`` + | ``end record;`` + | ``type C2 is new C1 with record`` + | ``Field3 : Integer;`` + | ``end record;`` + D. | ``type D1 is tagged record`` + | ``Field1 : Integer;`` + | ``end record;`` + | ``type D2 is new D1;`` + +.. container:: animate + + Explanations + + A. Cannot extend a non-tagged type + B. Correct + C. Components must have distinct names + D. Types derived from a tagged type must have an extension + diff --git a/courses/fundamentals_of_ada/170_tagged_derivation/03-extending_tagged_types.rst b/courses/fundamentals_of_ada/170_tagged_derivation/03-extending_tagged_types.rst new file mode 100644 index 000000000..1403ae593 --- /dev/null +++ b/courses/fundamentals_of_ada/170_tagged_derivation/03-extending_tagged_types.rst @@ -0,0 +1,204 @@ +======================== +Extending Tagged Types +======================== + +---------------------------------- +How Do You Extend a Tagged Type? +---------------------------------- + +* Premise of a tagged type is to :dfn:`extend` an existing type + +* In general, that means we want to add more fields + + * We can extend a :ada:`tagged` type by adding fields + + .. code:: Ada + + package Animals is + type Animal_T is tagged record + Age : Natural; + end record; + end Animals; + + with Animals; use Animals; + package Mammals is + type Mammal_T is new Animal_T with record + Number_Of_Legs : Natural; + end record; + end Mammals; + + with Mammals; use Mammals; + package Canines is + type Canine_T is new Mammal_T with record + Domesticated : Boolean; + end record; + end Canines; + +------------------ +Tagged Aggregate +------------------ + +* At initialization, all fields (including **inherited**) must have a **value** + + .. code:: Ada + + Animal : Animal_T := (Age => 1); + Mammal : Mammal_T := (Age => 2, + Number_Of_Legs => 2); + Canine : Canine_T := (Age => 2, + Number_Of_Legs => 4, + Domesticated => True); + +* But we can also "seed" the aggregate with a parent object + + .. code:: Ada + + Mammal := (Animal with Number_Of_Legs => 4); + Canine := (Animal with Number_Of_Legs => 4, + Domesticated => False); + Canine := (Mammal with Domesticated => True); + +---------------------- +Private Tagged Types +---------------------- + +* But data hiding says types should be private! + +* So we can define our base type as private + + .. container:: latex_environment tiny + + .. code:: Ada + + package Animals is + type Animal_T is tagged private; + function Get_Age (P : Animal_T) return Natural; + procedure Set_Age (P : in out Animal_T; A : Natural); + private + type Animal_T is tagged record + Age : Natural; + end record; + end Animals; + +* And still allow derivation + + .. container:: latex_environment tiny + + .. code:: Ada + + with Animals; + package Mammals is + type Mammal_T is new Animals.Animal_T with record + Number_Of_Legs : Natural; + end record; + +* But now the only way to get access to :ada:`Age` is with accessor subprograms + +-------------------- +Private Extensions +-------------------- + +* In the previous slide, we exposed the fields for :ada:`Mammal_T`! + +* Better would be to make the extension itself private + + .. code:: Ada + + package Mammals is + type Mammal_T is new Animals.Animal_T with private; + private + type Mammal_T is new Animals.Animal_T with record + Number_Of_Legs : Natural; + end record; + end Mammals; + +-------------------------------------- +Aggregates with Private Tagged Types +-------------------------------------- + +* Remember, an aggregate must specify values for all components + + * But with private types, we can't see all the components! + +* So we need to use the "seed" method: + + .. code:: Ada + + procedure Inside_Mammals_Pkg is + Animal : Animal_T := Animals.Create; + Mammal : Mammal_T; + begin + Mammal := (Animal with Number_Of_Legs => 4); + Mammal := (Animals.Create with Number_Of_Legs => 4); + end Inside_Mammals_Pkg; + +* Note that we cannot use :ada:`others => <>` for components that are not visible to us + + .. code:: Ada + + Mammal := (Number_Of_Legs => 4, + others => <>); -- Compile Error + +----------------- +Null Extensions +----------------- + +* To create a new type with no additional fields + + * We still need to "extend" the record - we just do it with an empty record + + .. code:: Ada + + type Dog_T is new Canine_T with null record; + + +* We still need to specify the "added" fields in an aggregate + + .. code:: Ada + + C : Canine_T := Canines.Create; + Dog1 : Dog_T := C; -- Compile Error + Dog2 : Dog_T := (C with null record); + +------ +Quiz +------ + +Given the following code: + + .. code::ada + + package Parents is + type Parent_T is tagged private; + function Create return Parent_T; + private + type Parent_T is tagged record + Id : Integer; + end record; + end Parents; + + with Parents; use Parents; + package Children is + P : Parent_T; + type Child_T is new Parent_T with record + Count : Natural; + end record; + function Create (C : Natural) return Child_T; + end Children; + +Which completion(s) of Create is (are) valid? + + A. :answermono:`function Create return Child_T is (Parents.Create with Count => 0);` + B. ``function Create return Child_T is (others => <>);`` + B. ``function Create return Child_T is (0, 0);`` + D. :answermono:`function Create return Child_T is (P with Count => 0);` + +.. container:: animate + + Explanations + + A. Correct - :ada:`Parents.Create` returns :ada:`Parent_T` + B. Cannot use :ada:`others` to complete private part of an aggregate + C. Aggregate has no visibility to :ada:`Id` field, so cannot assign + D. Correct - :ada:`P` is a :ada:`Parent_T` + diff --git a/courses/fundamentals_of_ada/170_tagged_derivation/99-summary.rst b/courses/fundamentals_of_ada/170_tagged_derivation/99-summary.rst new file mode 100644 index 000000000..7e55c5963 --- /dev/null +++ b/courses/fundamentals_of_ada/170_tagged_derivation/99-summary.rst @@ -0,0 +1,17 @@ +========= +Summary +========= + +--------- +Summary +--------- + +* Tagged derivation + + - Building block for OOP types in Ada + +* Primitives rules for tagged types are trickier + + - Primitives **forbidden** below freeze point + - **Unique** controlling parameter + - Tip: Keep the number of tagged type per package low diff --git a/courses/fundamentals_of_ada/175_multiple_inheritance.rst b/courses/fundamentals_of_ada/175_multiple_inheritance.rst new file mode 100644 index 000000000..d23d910dd --- /dev/null +++ b/courses/fundamentals_of_ada/175_multiple_inheritance.rst @@ -0,0 +1,39 @@ +********************** +Multiple Inheritance +********************** + +.. container:: PRELUDE BEGIN + +.. container:: PRELUDE ROLES + +.. role:: ada(code) + :language: Ada + +.. role:: C(code) + :language: C + +.. role:: cpp(code) + :language: C++ + +.. container:: PRELUDE SYMBOLS + +.. |rightarrow| replace:: :math:`\rightarrow` +.. |forall| replace:: :math:`\forall` +.. |exists| replace:: :math:`\exists` +.. |equivalent| replace:: :math:`\iff` +.. |le| replace:: :math:`\le` +.. |ge| replace:: :math:`\ge` +.. |lt| replace:: :math:`<` +.. |gt| replace:: :math:`>` +.. |checkmark| replace:: :math:`\checkmark` + +.. container:: PRELUDE REQUIRES + +.. container:: PRELUDE PROVIDES + +.. container:: PRELUDE END + +.. include:: 175_multiple_inheritance/01-introduction.rst +.. include:: 175_multiple_inheritance/02-interfaces.rst +.. include:: labs/175_multiple_inheritance.lab.rst +.. include:: 175_multiple_inheritance/99-summary.rst diff --git a/courses/fundamentals_of_ada/175_multiple_inheritance/01-introduction.rst b/courses/fundamentals_of_ada/175_multiple_inheritance/01-introduction.rst new file mode 100644 index 000000000..daa8659d3 --- /dev/null +++ b/courses/fundamentals_of_ada/175_multiple_inheritance/01-introduction.rst @@ -0,0 +1,58 @@ +============== +Introduction +============== + +------------------------------------------ +Multiple Inheritance Is Forbidden in Ada +------------------------------------------ + +* There are potential conflicts with multiple inheritance +* Some languages allow it: ambiguities have to be resolved when entities are referenced +* Ada forbids it to improve integration + +.. code:: Ada + + type Graphic is tagged record + X, Y : Float; + end record; + function Get_X (V : Graphic) return Float; + + type Shape is tagged record + X, Y : Float; + end record; + function Get_X (V : Shape) return Float; + + type Displayable_Shape is new Shape and Graphic with ... + +---------------------------------- +Multiple Inheritance - Safe Case +---------------------------------- + +* If only one type has concrete operations and fields, this is fine + + .. code:: Ada + + type Graphic is abstract tagged null record; + function Get_X (V : Graphic) return Float is abstract; + + type Shape is tagged record + X, Y : Float; + end record; + function Get_X (V : Shape) return Float; + + type Displayable_Shape is new Shape and Graphic with ... + +* This is the definition of an interface (as in Java) + + .. code:: Ada + + type Graphic is interface; + function Get_X (V : Graphic) return Float is abstract; + + type Shape is tagged record + X, Y : Float; + end record; + function Get_X (V : Shape) return Float; + + type Displayable_Shape is new Shape and Graphic with ... + diff --git a/courses/fundamentals_of_ada/175_multiple_inheritance/02-interfaces.rst b/courses/fundamentals_of_ada/175_multiple_inheritance/02-interfaces.rst new file mode 100644 index 000000000..10dbb9d8b --- /dev/null +++ b/courses/fundamentals_of_ada/175_multiple_inheritance/02-interfaces.rst @@ -0,0 +1,88 @@ +============ +Interfaces +============ + +-------------------- +Interfaces - Rules +-------------------- + +* An interface is a tagged type marked interface, containing + + - Abstract primitives + - Null primitives + - No fields + +* Null subprograms provide default empty bodies to primitives that can be overridden + + .. code:: Ada + + type I is interface; + procedure P1 (V : I) is abstract; + procedure P2 (V : access I) is abstract + function F return I is abstract; + procedure P3 (V : I) is null; + +* Note: null can be applied to any procedure (not only used for interfaces) + +---------------------- +Interface Derivation +---------------------- + +* An interface can be derived from another interface, adding primitives + + .. code:: Ada + + type I1 is interface; + procedure P1 (V : I) is abstract; + type I2 is interface and I1; + Procedure P2 (V : I) is abstract; + +* A tagged type can derive from several interfaces and can derive from one interface several times + + .. code:: Ada + + type I1 is interface; + type I2 is interface and I1; + type I3 is interface; + + type R is new I1 and I2 and I3 ... + +* A tagged type can derive from a single tagged type and several interfaces + + .. code:: Ada + + type I1 is interface; + type I2 is interface and I1; + type R1 is tagged null record; + + type R2 is new R1 and I1 and I2 ... + +------------------------ +Interfaces and Privacy +------------------------ + +* If the partial view of the type is tagged, then both the partial and the full view must expose the same interfaces + + .. code:: Ada + + package Types is + + type I1 is interface; + type R is new I1 with private; + + private + + type R is new I1 with record ... + +------------------------------------- +Limited Tagged Types and Interfaces +------------------------------------- + +* When a tagged type is limited in the hierarchy, the whole hierarchy has to be limited +* Conversions to interfaces are "just conversions to a view" + + - A view may have more constraints than the actual object + +* :ada:`limited` interfaces can be implemented by BOTH limited types and non-limited types +* Non-limited interfaces have to be implemented by non-limited types + diff --git a/courses/fundamentals_of_ada/175_multiple_inheritance/99-summary.rst b/courses/fundamentals_of_ada/175_multiple_inheritance/99-summary.rst new file mode 100644 index 000000000..501817b18 --- /dev/null +++ b/courses/fundamentals_of_ada/175_multiple_inheritance/99-summary.rst @@ -0,0 +1,18 @@ +========= +Summary +========= + +--------- +Summary +--------- + +* Interfaces must be used for multiple inheritance + + * Usually combined with :ada:`tagged` types, but not necessary + * By using only interfaces, only accessors are allowed + +* Typically there are other ways to do the same thing + + * In our example, the conversion routine could be common to simplify things + +* But interfaces force the compiler to determine when operations are missing diff --git a/courses/fundamentals_of_ada/adv_170_multiple_inheritance.rst b/courses/fundamentals_of_ada/adv_170_multiple_inheritance.rst deleted file mode 100644 index e3d69e112..000000000 --- a/courses/fundamentals_of_ada/adv_170_multiple_inheritance.rst +++ /dev/null @@ -1,205 +0,0 @@ -********************** -Multiple Inheritance -********************** - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - ------------------------------------------- -Multiple Inheritance Is Forbidden in Ada ------------------------------------------- - -* There are potential conflicts with multiple inheritance -* Some languages allow it: ambiguities have to be resolved when entities are referenced -* Ada forbids it to improve integration - -.. code:: Ada - - type Graphic is tagged record - X, Y : Float; - end record; - function Get_X (V : Graphic) return Float; - - type Shape is tagged record - X, Y : Float; - end record; - function Get_X (V : Shape) return Float; - - type Displayable_Shape is new Shape and Graphic with ... - ----------------------------------- -Multiple Inheritance - Safe Case ----------------------------------- - -* If only one type has concrete operations and fields, this is fine - - .. code:: Ada - - type Graphic is abstract tagged null record; - function Get_X (V : Graphic) return Float is abstract; - - type Shape is tagged record - X, Y : Float; - end record; - function Get_X (V : Shape) return Float; - - type Displayable_Shape is new Shape and Graphic with ... - -* This is the definition of an interface (as in Java) - - .. code:: Ada - - type Graphic is interface; - function Get_X (V : Graphic) return Float is abstract; - - type Shape is tagged record - X, Y : Float; - end record; - function Get_X (V : Shape) return Float; - - type Displayable_Shape is new Shape and Graphic with ... - -============ -Interfaces -============ - --------------------- -Interfaces - Rules --------------------- - -* An interface is a tagged type marked interface, containing - - - Abstract primitives - - Null primitives - - No fields - -* Null subprograms provide default empty bodies to primitives that can be overridden - - .. code:: Ada - - type I is interface; - procedure P1 (V : I) is abstract; - procedure P2 (V : access I) is abstract - function F return I is abstract; - procedure P3 (V : I) is null; - -* Note: null can be applied to any procedure (not only used for interfaces) - ----------------------- -Interface Derivation ----------------------- - -* An interface can be derived from another interface, adding primitives - - .. code:: Ada - - type I1 is interface; - procedure P1 (V : I) is abstract; - type I2 is interface and I1; - Procedure P2 (V : I) is abstract; - -* A tagged type can derive from several interfaces and can derive from one interface several times - - .. code:: Ada - - type I1 is interface; - type I2 is interface and I1; - type I3 is interface; - - type R is new I1 and I2 and I3 ... - -* A tagged type can derive from a single tagged type and several interfaces - - .. code:: Ada - - type I1 is interface; - type I2 is interface and I1; - type R1 is tagged null record; - - type R2 is new R1 and I1 and I2 ... - ------------------------- -Interfaces and Privacy ------------------------- - -* If the partial view of the type is tagged, then both the partial and the full view must expose the same interfaces - - .. code:: Ada - - package Types is - - type I1 is interface; - type R is new I1 with private; - - private - - type R is new I1 with record ... - -------------------------------------- -Limited Tagged Types and Interfaces -------------------------------------- - -* When a tagged type is limited in the hierarchy, the whole hierarchy has to be limited -* Conversions to interfaces are "just conversions to a view" - - - A view may have more constraints than the actual object - -* :ada:`limited` interfaces can be implemented by BOTH limited types and non-limited types -* Non-limited interfaces have to be implemented by non-limited types - -======== -Lab -======== - -.. include:: labs/adv_170_multiple_inheritance.lab.rst - -========= -Summary -========= - ---------- -Summary ---------- - -* Interfaces must be used for multiple inheritance - - * Usually combined with :ada:`tagged` types, but not necessary - * By using only interfaces, only accessors are allowed - -* Typically there are other ways to do the same thing - - * In our example, the conversion routine could be common to simplify things - -* But interfaces force the compiler to determine when operations are missing diff --git a/courses/fundamentals_of_ada/advanced.txt b/courses/fundamentals_of_ada/advanced.txt index 9f3c81732..40dbda808 100644 --- a/courses/fundamentals_of_ada/advanced.txt +++ b/courses/fundamentals_of_ada/advanced.txt @@ -9,7 +9,7 @@ adv_120_advanced_privacy.rst 140_access_types-advanced.rst 160_genericity.rst 170_tagged_derivation.rst -adv_170_multiple_inheritance.rst +175_multiple_inheritance.rst 180_polymorphism.rst 190_exceptions-in_depth.rst 240_tasking_in_depth.rst diff --git a/courses/fundamentals_of_ada/intro_170_tagged_derivation.rst b/courses/fundamentals_of_ada/intro_170_tagged_derivation.rst deleted file mode 100644 index a1a462a96..000000000 --- a/courses/fundamentals_of_ada/intro_170_tagged_derivation.rst +++ /dev/null @@ -1,564 +0,0 @@ -***************** -Tagged Derivation -***************** - -.. container:: PRELUDE BEGIN - -.. container:: PRELUDE ROLES - -.. role:: ada(code) - :language: Ada - -.. role:: C(code) - :language: C - -.. role:: cpp(code) - :language: C++ - -.. container:: PRELUDE SYMBOLS - -.. |rightarrow| replace:: :math:`\rightarrow` -.. |forall| replace:: :math:`\forall` -.. |exists| replace:: :math:`\exists` -.. |equivalent| replace:: :math:`\iff` -.. |le| replace:: :math:`\le` -.. |ge| replace:: :math:`\ge` -.. |lt| replace:: :math:`<` -.. |gt| replace:: :math:`>` -.. |checkmark| replace:: :math:`\checkmark` - -.. container:: PRELUDE REQUIRES - -.. container:: PRELUDE PROVIDES - -.. container:: PRELUDE END - -============== -Introduction -============== - ---------------------------------------------- -Object-Oriented Programming with Tagged Types ---------------------------------------------- - -* For :ada:`record` types - - .. code:: Ada - - type T is tagged record - ... - -* Child types can add new components (*attributes*) -* Object of a child type can be **substituted** for base type -* Primitive (*method*) can :dfn:`dispatch` **at run-time** depending on the type at call-site -* Types can be **extended** by other packages - - - Conversion and qualification to base type is allowed - -* Private data is encapsulated through **privacy** - ------------------------------- -Tagged Derivation Ada Vs C++ ------------------------------- - -.. container:: columns - - .. container:: column - - .. code:: Ada - - type T1 is tagged record - Member1 : Integer; - end record; - - procedure Attr_F (This : T1); - - type T2 is new T1 with record - Member2 : Integer; - end record; - - overriding procedure Attr_F ( - This : T2); - procedure Attr_F2 (This : T2); - - .. container:: column - - .. code:: C++ - - class T1 { - public: - int Member1; - virtual void Attr_F(void); - }; - - class T2 : public T1 { - public: - int Member2; - virtual void Attr_F(void); - virtual void Attr_F2(void); - }; - -================= -Tagged Derivation -================= - ---------------------------------- -Difference with Simple Derivation ---------------------------------- - -* Tagged derivation **can** change the structure of a type - - - Keywords :ada:`tagged record` and :ada:`with record` - - .. code:: Ada - - type Root is tagged record - F1 : Integer; - end record; - - type Child is new Root with record - F2 : Integer; - end record; - --------------- -Type Extension --------------- - -* A tagged derivation **has** to be a type extension - - - Use :ada:`with null record` if there are no additional components - - .. code:: Ada - - type Child is new Root with null record; - type Child is new Root; -- illegal - -* Conversion is only allowed from **child to parent** - - .. code:: Ada - - V1 : Root; - V2 : Child; - ... - V1 := Root (V2); - V2 := Child (V1); -- illegal - -`Click here for more information on extending private types `_ - ------------- -Primitives ------------- - -* Child **cannot remove** a primitive -* Child **can add** new primitives -* :dfn:`Controlling parameter` - - - Parameters the subprogram is a primitive of - - For :ada:`tagged` types, all should have the **same type** - - .. code:: Ada - - type Root1 is tagged null record; - type Root2 is tagged null record; - - procedure P1 (V1 : Root1; - V2 : Root1); - procedure P2 (V1 : Root1; - V2 : Root2); -- illegal - -------------------------------- -Freeze Point for Tagged Types -------------------------------- - -* Freeze point definition does not change - - - A variable of the type is declared - - The type is derived - - The end of the scope is reached - -* Declaring tagged type primitives past freeze point is **forbidden** - -.. code:: Ada - - type Root is tagged null record; - - procedure Prim (V : Root); - - type Child is new Root with null record; -- freeze root - - procedure Prim2 (V : Root); -- illegal - - V : Child; -- freeze child - - procedure Prim3 (V : Child); -- illegal - ------------------- -Tagged Aggregate ------------------- - -* At initialization, all fields (including **inherited**) must have a **value** - - .. code:: Ada - - type Root is tagged record - F1 : Integer; - end record; - - type Child is new Root with record - F2 : Integer; - end record; - - V : Child := (F1 => 0, F2 => 0); - -* For **private types** use :dfn:`aggregate extension` - - - Copy of a parent instance - - Use :ada:`with null record` absent new fields - - .. code:: Ada - - V2 : Child := (Parent_Instance with F2 => 0); - V3 : Empty_Child := (Parent_Instance with null record); - -`Click here for more information on aggregates of private extensions `_ - ---------------------- -Overriding Indicators ---------------------- - -* Optional :ada:`overriding` and :ada:`not overriding` indicators - - .. code:: Ada - - type Shape_T is tagged record - Name : String (1..10); - end record; - - -- primitives of "Shape_T" - procedure Set_Name (S : in out Shape_T); - function Name (S : Shape_T) return String; - - -- Derive "Point" from Shape_T - type Point is new Shape_T with record - Origin : Coord_T; - end Point; - - -- We want to _change_ the behavior of Set_Name - overriding procedure Set_Name (P : in out Point_T); - -- We want to _add_ a new primitive - not overriding Origin (P : Point_T) return Point_T; - -- We get "Name" for free - -.. - language_version 2005 - ------------------ -Prefix Notation ------------------ - -* Tagged types primitives can be called as usual -* The call can use prefixed notation - - - **If** the first argument is a controlling parameter - - No need for :ada:`use` or :ada:`use type` for visibility - - .. code:: Ada - - -- Prim1 visible even without *use Pkg* - X.Prim1; - - declare - use Pkg; - begin - Prim1 (X); - end; - -.. - language_version 2012 - ------- -Quiz ------- - -.. include:: quiz/tagged_primitives/quiz.rst - ------- -Quiz ------- - -.. include:: quiz/tagged_dot_and_with/quiz.rst - ------- -Quiz ------- - -Which code block(s) is (are) legal? - -.. container:: columns - - .. container:: column - - A. | ``type A1 is record`` - | ``Field1 : Integer;`` - | ``end record;`` - | ``type A2 is new A1 with null record;`` - B. | :answermono:`type B1 is tagged record` - | :answermono:`Field2 : Integer;` - | :answermono:`end record;` - | :answermono:`type B2 is new B1 with record` - | :answermono:`Field2b : Integer;` - | :answermono:`end record;` - - .. container:: column - - C. | ``type C1 is tagged record`` - | ``Field3 : Integer;`` - | ``end record;`` - | ``type C2 is new C1 with record`` - | ``Field3 : Integer;`` - | ``end record;`` - D. | ``type D1 is tagged record`` - | ``Field1 : Integer;`` - | ``end record;`` - | ``type D2 is new D1;`` - -.. container:: animate - - Explanations - - A. Cannot extend a non-tagged type - B. Correct - C. Components must have distinct names - D. Types derived from a tagged type must have an extension - -======== -Lab -======== - -.. include:: labs/intro_170_tagged_derivation.lab.rst - -========= -Summary -========= - ---------- -Summary ---------- - -* Tagged derivation - - - Building block for OOP types in Ada - -* Primitives rules for tagged types are trickier - - - Primitives **forbidden** below freeze point - - **Unique** controlling parameter - - Tip: Keep the number of tagged type per package low - -================================================= -Additional Information - Extending Tagged Types -================================================= - ----------------------------------- -How Do You Extend a Tagged Type? ----------------------------------- - -* Premise of a tagged type is to :dfn:`extend` an existing type - -* In general, that means we want to add more fields - - * We can extend a :ada:`tagged` type by adding fields - - .. code:: Ada - - package Animals is - type Animal_T is tagged record - Age : Natural; - end record; - end Animals; - - with Animals; use Animals; - package Mammals is - type Mammal_T is new Animal_T with record - Number_Of_Legs : Natural; - end record; - end Mammals; - - with Mammals; use Mammals; - package Canines is - type Canine_T is new Mammal_T with record - Domesticated : Boolean; - end record; - end Canines; - -------------------- -Tagged Aggregates -------------------- - -* At initialization, all fields (including **inherited**) must have a **value** - - .. code:: Ada - - Animal : Animal_T := (Age => 1); - Mammal : Mammal_T := (Age => 2, - Number_Of_Legs => 2); - Canine : Canine_T := (Age => 2, - Number_Of_Legs => 4, - Domesticated => True); - -* But we can also "seed" the aggregate with a parent object - - .. code:: Ada - - Mammal := (Animal with Number_Of_Legs => 4); - Canine := (Animal with Number_Of_Legs => 4, - Domesticated => False); - Canine := (Mammal with Domesticated => True); - ----------------------- -Private Tagged Types ----------------------- - -* But data hiding says types should be private! - -* So we can define our base type as private - - .. container:: latex_environment tiny - - .. code:: Ada - - package Animals is - type Animal_T is tagged private; - function Get_Age (P : Animal_T) return Natural; - procedure Set_Age (P : in out Animal_T; A : Natural); - private - type Animal_T is tagged record - Age : Natural; - end record; - end Animals; - -* And still allow derivation - - .. container:: latex_environment tiny - - .. code:: Ada - - with Animals; - package Mammals is - type Mammal_T is new Animals.Animal_T with record - Number_Of_Legs : Natural; - end record; - -* But now the only way to get access to :ada:`Age` is with accessor subprograms - --------------------- -Private Extensions --------------------- - -* In the previous slide, we exposed the fields for :ada:`Mammal_T`! - -* Better would be to make the extension itself private - - .. code:: Ada - - package Mammals is - type Mammal_T is new Animals.Animal_T with private; - private - type Mammal_T is new Animals.Animal_T with record - Number_Of_Legs : Natural; - end record; - end Mammals; - -`Click here to go back to Type Extension `_ - --------------------------------------- -Aggregates with Private Tagged Types --------------------------------------- - -* Remember, an aggregate must specify values for all components - - * But with private types, we can't see all the components! - -* So we need to use the "seed" method: - - .. code:: Ada - - procedure Inside_Mammals_Pkg is - Animal : Animal_T := Animals.Create; - Mammal : Mammal_T; - begin - Mammal := (Animal with Number_Of_Legs => 4); - Mammal := (Animals.Create with Number_Of_Legs => 4); - end Inside_Mammals_Pkg; - -* Note that we cannot use :ada:`others => <>` for components that are not visible to us - - .. code:: Ada - - Mammal := (Number_Of_Legs => 4, - others => <>); -- Compile Error - ------------------ -Null Extensions ------------------ - -* To create a new type with no additional fields - - * We still need to "extend" the record - we just do it with an empty record - - .. code:: Ada - - type Dog_T is new Canine_T with null record; - - -* We still need to specify the "added" fields in an aggregate - - .. code:: Ada - - C : Canine_T := Canines.Create; - Dog1 : Dog_T := C; -- Compile Error - Dog2 : Dog_T := (C with null record); - -`Click here to go back to Tagged Aggregate `_ - ------- -Quiz ------- - -Given the following code: - - .. code::ada - - package Parents is - type Parent_T is tagged private; - function Create return Parent_T; - private - type Parent_T is tagged record - Id : Integer; - end record; - end Parents; - - with Parents; use Parents; - package Children is - P : Parent_T; - type Child_T is new Parent_T with record - Count : Natural; - end record; - function Create (C : Natural) return Child_T; - end Children; - -Which completion(s) of Create is (are) valid? - - A. :answermono:`function Create return Child_T is (Parents.Create with Count => 0);` - B. ``function Create return Child_T is (others => <>);`` - B. ``function Create return Child_T is (0, 0);`` - D. :answermono:`function Create return Child_T is (P with Count => 0);` - -.. container:: animate - - Explanations - - A. Correct - :ada:`Parents.Create` returns :ada:`Parent_T` - B. Cannot use :ada:`others` to complete private part of an aggregate - C. Aggregate has no visibility to :ada:`Id` field, so cannot assign - D. Correct - :ada:`P` is a :ada:`Parent_T` diff --git a/courses/fundamentals_of_ada/labs/intro_170_tagged_derivation.lab.rst b/courses/fundamentals_of_ada/labs/170_tagged_derivation-simple.lab.rst similarity index 68% rename from courses/fundamentals_of_ada/labs/intro_170_tagged_derivation.lab.rst rename to courses/fundamentals_of_ada/labs/170_tagged_derivation-simple.lab.rst index e220b768a..e8c42d728 100644 --- a/courses/fundamentals_of_ada/labs/intro_170_tagged_derivation.lab.rst +++ b/courses/fundamentals_of_ada/labs/170_tagged_derivation-simple.lab.rst @@ -1,3 +1,7 @@ +======== +Lab +======== + ----------------------- Tagged Derivation Lab ----------------------- @@ -21,16 +25,16 @@ Tagged Derivation Lab Tagged Derivation Lab Solution - Types (Spec) ----------------------------------------------- -.. container:: source_include labs/answers/intro_170_tagged_derivation.txt :start-after:--Types_Spec :end-before:--Types_Spec :code:Ada :number-lines:1 +.. container:: source_include labs/answers/170_tagged_derivation-simple.txt :start-after:--Types_Spec :end-before:--Types_Spec :code:Ada :number-lines:1 ------------------------------------------------------- Tagged Derivation Lab Solution - Types (Partial Body) ------------------------------------------------------- -.. container:: source_include labs/answers/intro_170_tagged_derivation.txt :start-after:--Types_Body :end-before:--Types_Body :code:Ada :number-lines:1 +.. container:: source_include labs/answers/170_tagged_derivation-simple.txt :start-after:--Types_Body :end-before:--Types_Body :code:Ada :number-lines:1 --------------------------------------- Tagged Derivation Lab Solution - Main --------------------------------------- -.. container:: source_include labs/answers/intro_170_tagged_derivation.txt :start-after:--Main :end-before:--Main :code:Ada :number-lines:1 +.. container:: source_include labs/answers/170_tagged_derivation-simple.txt :start-after:--Main :end-before:--Main :code:Ada :number-lines:1 diff --git a/courses/fundamentals_of_ada/labs/170_tagged_derivation.lab.rst b/courses/fundamentals_of_ada/labs/170_tagged_derivation.lab.rst index e285afc4b..4b73bef9d 100644 --- a/courses/fundamentals_of_ada/labs/170_tagged_derivation.lab.rst +++ b/courses/fundamentals_of_ada/labs/170_tagged_derivation.lab.rst @@ -1,3 +1,7 @@ +======== +Lab +======== + ----------------------- Tagged Derivation Lab ----------------------- diff --git a/courses/fundamentals_of_ada/labs/adv_170_multiple_inheritance.lab.rst b/courses/fundamentals_of_ada/labs/175_multiple_inheritance.lab.rst similarity index 61% rename from courses/fundamentals_of_ada/labs/adv_170_multiple_inheritance.lab.rst rename to courses/fundamentals_of_ada/labs/175_multiple_inheritance.lab.rst index 3ccd5c2fc..81b12ddcd 100644 --- a/courses/fundamentals_of_ada/labs/adv_170_multiple_inheritance.lab.rst +++ b/courses/fundamentals_of_ada/labs/175_multiple_inheritance.lab.rst @@ -1,3 +1,7 @@ +======== +Lab +======== + ------------------------------------------ Multiple Inheritance Lab ------------------------------------------ @@ -27,41 +31,41 @@ Multiple Inheritance Lab Inheritance Lab Solution - Data Types --------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Types :end-before:--Types :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Types :end-before:--Types :code:Ada :number-lines:1 --------------------------------------- Inheritance Lab Solution - Shapes --------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Shapes :end-before:--Shapes :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Shapes :end-before:--Shapes :code:Ada :number-lines:1 ------------------------------------------- Inheritance Lab Solution - Drawing (Spec) ------------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Drawing_Spec :end-before:--Drawing_Spec :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Drawing_Spec :end-before:--Drawing_Spec :code:Ada :number-lines:1 ------------------------------------------- Inheritance Lab Solution - Drawing (Body) ------------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Drawing_Body :end-before:--Drawing_Body :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Drawing_Body :end-before:--Drawing_Body :code:Ada :number-lines:1 --------------------------------------------- Inheritance Lab Solution - Printable Object --------------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Printable_Object :end-before:--Printable_Object :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Printable_Object :end-before:--Printable_Object :code:Ada :number-lines:1 --------------------------------------------- Inheritance Lab Solution - Rectangle --------------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Rectangle :end-before:--Rectangle :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Rectangle :end-before:--Rectangle :code:Ada :number-lines:1 --------------------------------------------- Inheritance Lab Solution - Main --------------------------------------------- -.. container:: source_include labs/answers/adv_170_multiple_inheritance.txt :start-after:--Main :end-before:--Main :code:Ada :number-lines:1 +.. container:: source_include labs/answers/175_multiple_inheritance.txt :start-after:--Main :end-before:--Main :code:Ada :number-lines:1 diff --git a/courses/fundamentals_of_ada/labs/answers/intro_170_tagged_derivation.txt b/courses/fundamentals_of_ada/labs/answers/170_tagged_derivation-simple.txt similarity index 100% rename from courses/fundamentals_of_ada/labs/answers/intro_170_tagged_derivation.txt rename to courses/fundamentals_of_ada/labs/answers/170_tagged_derivation-simple.txt diff --git a/courses/fundamentals_of_ada/labs/answers/adv_170_multiple_inheritance.txt b/courses/fundamentals_of_ada/labs/answers/175_multiple_inheritance.txt similarity index 100% rename from courses/fundamentals_of_ada/labs/answers/adv_170_multiple_inheritance.txt rename to courses/fundamentals_of_ada/labs/answers/175_multiple_inheritance.txt diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/base_types.ads b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/base_types.ads similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/base_types.ads rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/base_types.ads diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/default.gpr b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/default.gpr similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/default.gpr rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/default.gpr diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/geometry.ads b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/geometry.ads similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/geometry.ads rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/geometry.ads diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/line_draw.adb b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/line_draw.adb similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/line_draw.adb rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/line_draw.adb diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/line_draw.ads b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/line_draw.ads similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/line_draw.ads rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/line_draw.ads diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/main.adb b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/main.adb similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/main.adb rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/main.adb diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/printable_object.adb b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/printable_object.adb similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/printable_object.adb rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/printable_object.adb diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/printable_object.ads b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/printable_object.ads similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/printable_object.ads rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/printable_object.ads diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/rectangle.adb b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/rectangle.adb similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/rectangle.adb rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/rectangle.adb diff --git a/courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/rectangle.ads b/courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/rectangle.ads similarity index 100% rename from courses/fundamentals_of_ada/labs/prompts/adv_170_multiple_inheritance/rectangle.ads rename to courses/fundamentals_of_ada/labs/prompts/175_multiple_inheritance/rectangle.ads diff --git a/courses/fundamentals_of_ada/opat.txt b/courses/fundamentals_of_ada/opat.txt index d9012a5a0..d2807d5ea 100644 --- a/courses/fundamentals_of_ada/opat.txt +++ b/courses/fundamentals_of_ada/opat.txt @@ -13,7 +13,7 @@ 110_private_types.rst 130_program_structure.rst 135_visibility.rst -intro_170_tagged_derivation.rst +170_tagged_derivation-intro.rst 190_exceptions.rst 140_access_types.rst 160_genericity.rst diff --git a/courses/fundamentals_of_ada/standard_course.txt b/courses/fundamentals_of_ada/standard_course.txt index e34585337..51c6e04fd 100644 --- a/courses/fundamentals_of_ada/standard_course.txt +++ b/courses/fundamentals_of_ada/standard_course.txt @@ -16,7 +16,7 @@ 135_visibility.rst 140_access_types.rst 160_genericity.rst -intro_170_tagged_derivation.rst +170_tagged_derivation-intro.rst 180_polymorphism.rst 190_exceptions.rst 230_interfacing_with_c.rst