Skip to content

Slides/195 chapterization of fringe modules #489

New issue

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

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

Already on GitHub? Sign in to your account

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
249 changes: 4 additions & 245 deletions courses/fundamentals_of_ada/260_controlled_types.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,249 +36,8 @@ Controlled Types

.. container:: PRELUDE END

==============
Introduction
==============

-------------------------
Constructor / Destructor
-------------------------

* Possible to specify behavior of object initialization, finalization, and assignment

- Based on type definition
- Type must derive from `Controlled` or `Limited_Controlled` in package `Ada.Finalization`

* This derived type is called a *controlled type*

- User may override any or all subprograms in `Ada.Finalization`
- Default implementation is a null body

==================
Ada.Finalization
==================

---------------
Package Spec
---------------

.. code:: Ada

package Ada.Finalization is

type Controlled is abstract tagged private;
procedure Initialize (Object : in out Controlled)
is null;
procedure Adjust (Object : in out Controlled)
is null;
procedure Finalize (Object : in out Controlled)
is null;

type Limited_Controlled is abstract tagged limited private;
procedure Initialize (Object : in out Limited_Controlled)
is null;
procedure Finalize (Object : in out Limited_Controlled)
is null;

private
-- implementation defined
end Ada.Finalization;

-------
Uses
-------

* Prevent "resource leak"

- Logic centralized in service rather than distributed across clients

* Examples: heap reclamation, "mutex" unlocking
* User-defined assignment

----------------
Initialization
----------------

* Subprogram `Initialize` invoked after object created

- Either by object declaration or allocator
- Only if no explicit initialization expression

* Often default initialization expressions on record components are sufficient

- No need for an explicit call to `Initialize`

* Similar to C++ constructor

----------------
Finalization
----------------

* Subprogram `Finalize` invoked just before object is destroyed

- Leaving the scope of a declared object
- Unchecked deallocation of an allocated object

* Similar to C++ destructor

------------
Assignment
------------

* Subprogram `Adjust` invoked as part of an assignment operation
* Assignment statement `Target := Source;` is basically:

- `Finalize (Target)`
- Copy Source to Target
- `Adjust (Target)`
- *Actual rules are more complicated, e.g. to allow cases where Target and Source are the same object*

* Typical situations where objects are access values

- `Finalize` does unchecked deallocation or decrements a reference count
- The copy step copies the access value
- `Adjust` either clones a "deep copy" of the referenced object or increments a reference count

=========
Example
=========

----------------------------------
Unbounded String Via Access Type
----------------------------------

* Type contains a pointer to a string type
* We want the provider to allocate and free memory "safely"

- No sharing
- `Adjust` allocates referenced String
- `Finalize` frees the referenced String
- Assignment deallocates target string and assigns copy of source string to target string

------------------------
Unbounded String Usage
------------------------

.. code:: Ada

with Unbounded_String_Pkg; use Unbounded_String_Pkg;
procedure Test is
U1 : Ustring_T;
begin
U1 := To_Ustring_T ("Hello");
declare
U2 : Ustring_T;
begin
U2 := To_Ustring_T ("Goodbye");
U1 := U2; -- Reclaims U1 memory
end; -- Reclaims U2 memory
end Test; -- Reclaims U1 memory

-----------------------------
Unbounded String Definition
-----------------------------

.. code:: Ada

with Ada.Finalization; use Ada.Finalization;
package Unbounded_String_Pkg is
-- Implement unbounded strings
type Ustring_T is private;
function "=" (L, R : Ustring_T) return Boolean;
function To_Ustring_T (Item : String) return Ustring_T;
function To_String (Item : Ustring_T) return String;
function Length (Item : Ustring_T) return Natural;
function "&" (L, R : Ustring_T) return Ustring_T;
private
type String_Ref is access String;
type Ustring_T is new Controlled with record
Ref : String_Ref := new String (1 .. 0);
end record;
procedure Finalize (Object : in out Ustring_T);
procedure Adjust (Object : in out Ustring_T);
end Unbounded_String_Pkg;

---------------------------------
Unbounded String Implementation
---------------------------------

.. code:: Ada

with Ada.Unchecked_Deallocation;
package body Unbounded_String_Pkg is
procedure Free_String is new Ada.Unchecked_Deallocation
(String, String_Ref);

function "=" (L, R : Ustring_T) return Boolean is
(L.Ref.all = R.Ref.all);

function To_Ustring_T (Item : String) return Ustring_T is
(Controlled with Ref => new String'(Item));

function To_String (Item : Ustring_T) return String is
(Item.Ref.all);

function Length (Item : Ustring_T) return Natural is
(Item.Ref.all'Length);

function "&" (L, R : Ustring_T) return Ustring_T is
(Controlled with Ref => new String'(L.Ref.all & R.Ref.all);

procedure Finalize (Object : in out Ustring_T) is
begin
Free_String (Object.Ref);
end Finalize;

procedure Adjust (Object : in out Ustring_T) is
begin
Object.Ref := new String'(Object.Ref.all);
end Adjust;
end Unbounded_String_Pkg;

------------------
Finalizable Aspect
------------------

* Uses the GNAT-specific :ada:`with Finalizable` aspect

.. code:: Ada

type Ctrl is record
Id : Natural := 0;
end record
with Finalizable => (Initialize => Initialize,
Adjust => Adjust,
Finalize => Finalize,
Relaxed_Finalization => True);

procedure Adjust (Obj : in out Ctrl);
procedure Finalize (Obj : in out Ctrl);
procedure Initialize (Obj : in out Ctrl);

* :ada:`Initialize`, :ada:`Adjust` same definition as previously
* :ada:`Finalize` has the :ada:`No_Raise` aspect: it cannot raise exceptions
* :ada:`Relaxed_Finalization`

* Performance on-par with C++'s destructor
* No automatic finalization of **heap-allocated** objects

========
Lab
========

.. include:: 260_controlled_types/01-introduction.rst
.. include:: 260_controlled_types/02-ada_finalization.rst
.. include:: 260_controlled_types/03-example.rst
.. include:: labs/260_controlled_types.lab.rst

=========
Summary
=========

---------
Summary
---------

* Controlled types allow access to object construction, assignment, destruction
* `Ada.Finalization` can be expensive to use

- Other mechanisms may be more efficient

* But require more rigor in usage
.. include:: 260_controlled_types/99-summary.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
==============
Introduction
==============

-------------------------
Constructor / Destructor
-------------------------

* Possible to specify behavior of object initialization, finalization, and assignment

- Based on type definition
- Type must derive from `Controlled` or `Limited_Controlled` in package `Ada.Finalization`

* This derived type is called a *controlled type*

- User may override any or all subprograms in `Ada.Finalization`
- Default implementation is a null body

Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
==================
Ada.Finalization
==================

---------------
Package Spec
---------------

.. code:: Ada

package Ada.Finalization is

type Controlled is abstract tagged private;
procedure Initialize (Object : in out Controlled)
is null;
procedure Adjust (Object : in out Controlled)
is null;
procedure Finalize (Object : in out Controlled)
is null;

type Limited_Controlled is abstract tagged limited private;
procedure Initialize (Object : in out Limited_Controlled)
is null;
procedure Finalize (Object : in out Limited_Controlled)
is null;

private
-- implementation defined
end Ada.Finalization;

-------
Uses
-------

* Prevent "resource leak"

- Logic centralized in service rather than distributed across clients

* Examples: heap reclamation, "mutex" unlocking
* User-defined assignment

----------------
Initialization
----------------

* Subprogram `Initialize` invoked after object created

- Either by object declaration or allocator
- Only if no explicit initialization expression

* Often default initialization expressions on record components are sufficient

- No need for an explicit call to `Initialize`

* Similar to C++ constructor

----------------
Finalization
----------------

* Subprogram `Finalize` invoked just before object is destroyed

- Leaving the scope of a declared object
- Unchecked deallocation of an allocated object

* Similar to C++ destructor

------------
Assignment
------------

* Subprogram `Adjust` invoked as part of an assignment operation
* Assignment statement `Target := Source;` is basically:

- `Finalize (Target)`
- Copy Source to Target
- `Adjust (Target)`
- *Actual rules are more complicated, e.g. to allow cases where Target and Source are the same object*

* Typical situations where objects are access values

- `Finalize` does unchecked deallocation or decrements a reference count
- The copy step copies the access value
- `Adjust` either clones a "deep copy" of the referenced object or increments a reference count

Loading
Loading