In particular, about the feature of Polymorphism
, this is not a unique feature of OOP
but one of the common general concepts of the field of computer science in general. And expressing Polymorphism
is taken care of in all programming environments including Procedural Programming
and Functional Programming
.
In an earlier article of the Self- Taught Web Programming Series Naturally , I tried to introduce the general definition and logic types that represent Polymorphism
when it comes to the OOP
programming paradigm. Among the logical types representing Polymorphism
synthesized by Wikipedia
, here we have seen Sub-Typing Polymorphism
appear with the concept of Type'Class
.
In addition, the remaining representation logic types are Ad-hoc Polymorphism
and Parametric Polymorphism
supported by other features of the language, including:
Overloading Sub-program
– redefine different versions of the samesub-program
name with differentsignature
sets, including parameter data types and return data types (if any) .Generic Type
– uses the abstract symbolic nameType
for the type operation to represent any data type used as parameters tosub-program
andpackage
. Then, at each time we write code usingsub-program
andpackage
, we can specify a specific data type at the place ofType
depending on our needs.
Overloading Sub-programs
Here we will do a small example encapsulating the main.adb
launch file with the procedure
name Put_Total
which will be overload
with the signature
respectively: Put_Total (String, String)
and Put_Total (Integer, Integer)
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | with Ada.Text_IO; use Ada.Text_IO; with Humanity; use Humanity; procedure Main is procedure Put_Total (First, Second : in String) is begin Put_Line (First & " " & Second); end Put_Total; procedure Put_Total (First, Second : in Integer) is begin Put_Line ("Total : " & Integer'Image (First + Second)); end Put_Total; begin Put_Total ("Try", "Best"); Put_Total (1, 2); end Main; |
1 2 3 | Try Best Total : 3 |
overloading function
is no different from procedure
, as long as we create different signature
for each version of the function
definition of the same name. The only funtion
is that for the function, we will have signature
including the return
data type. And we probably won’t need to write more example code for funtion
.
Generic Sub-programs
Let’s start with a simple example, defining the generic type
used for a sub-program
.
1 2 3 4 5 6 | src ├── main.adb └── printer ├── printer.adb └── printer.ads |
1 2 3 4 5 | package Printer is generic type T is private; procedure Print (Value : in T); end Printer; |
1 2 3 4 5 6 7 8 9 10 11 | with Ada.Text_IO; use Ada.Text_IO; package body Printer is procedure Print (Value : in T) is begin Put_Line ("Value : " & T'Image (Value)); end Print; end Printer; |
So we have type T
defined as a generic type
and used to type the parameter Value
. Now when writing code using Print
, we can specify a specific data type depending on the intended use.
1 2 3 4 5 6 7 8 9 10 | with Printer; use Printer; procedure Main is procedure Print_Integer is new Print (T => Integer); procedure Print_Float is new Print (T => Float); begin Print_Integer (123456789); Print_Float (12.3456789); end Main; |
Note about the GNAT compiler – To use the
Image
property of any typeT
, we will need to specify the compiler mode of operation using the latest version of theAda
language .
1 2 3 | gprbuild -gnat2020 learn_ada.gpr cd obj && main && cd .. |
1 2 3 | Value : 123456789 Value : 1.23457E+01 |
Great.. So we didn’t have to repeat the code that defines the Print
program for each data type. And in case we need to use more generic
parameters, we just need to define more generic type
similar to T
.
Another note, is that when using generic sub-program
as above, we don’t necessarily need to give different names to specific sub-program
, but can be written in overloading
form with the same name.
1 2 3 4 5 6 7 8 9 10 | with Printer; use Printer; procedure Main is procedure Print_Value is new Print (T => Integer); procedure Print_Value is new Print (T => Float); begin Print_Value (123456789); Print_Value (12.3456789); end Main; |
Generic Package
In case we want to use generic type
in the definition of record
, we will need to move the declaration of generic type
outside the package
. This will indicate that – this package
is designed to be generic.
1 2 3 4 5 6 | src ├── list │ ├── list.adb │ └── list.ads └── main.adb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | generic type T is private; package List is type Item; type Item_Access is access Item; -- - - - - - - - - - - - - - type Container is record Head_Access : Item_Access; end record; type Item is record Value : T; Next_Access : Item_Access; end record; -- - - - - - - - - - - - - - procedure Add_Value ( List_Container : in out Container ; New_Value : in T ); procedure Print_All (List_Container : in Container); end List; |
Here is the example code of the access
pointer article we went through earlier that is rewritten with generic type
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | with Ada.Text_IO; use Ada.Text_IO; package body List is procedure Add_Value ( List_Container : in out Container ; New_Value : in T ) -- no return is New_Access : Item_Access; begin New_Access := new Item'(New_Value, List_Container.Head_Access); List_Container.Head_Access := New_Access; end Add_Value; procedure Print_All (List_Container : in Container) is Current_Access : Item_Access; begin Current_Access := List_Container.Head_Access; Put ("List : "); while Current_Access /= null loop Put (T'Image (Current_Access.Value) & " "); Current_Access := Current_Access.Next_Access; end loop; end Print_All; end List; |
And when writing code using generic package
, we also use the new
syntax to specify a specific data type for all locations using T
in the definition of the package
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | with List; procedure Main is package Integer_List is new List (T => Integer); Number_List : Integer_List.Container; New_Access : Integer_List.Item_Access; begin Number_List := (Head_Access => null); -- add new items Integer_List.Add_Value (Number_List, 0); Integer_List.Add_Value (Number_List, 1); Integer_List.Add_Value (Number_List, 2); -- print the list Integer_List.Print_All (Number_List); end Main; |
1 2 | List : 2 1 0 |
In the next article, we will learn about a very special tool of Ada
– present in a handful of other programming languages.