Object-oriented programming

Simple type extension

Goal: work with type extensions using record types containing numeric components.

Steps:

  1. Implement the Type_Extensions package.

    1. Declare the record type T_Float.

    2. Declare the record type T_Mixed

    3. Implement the Init function for the T_Float type with a floating-point input parameter.

    4. Implement the Init function for the T_Float type with an integer input parameter.

    5. Implement the Image function for the T_Float type.

    6. Implement the Init function for the T_Mixed type with a floating-point input parameter.

    7. Implement the Init function for the T_Mixed type with an integer input parameter.

    8. Implement the Image function for the T_Mixed type.

Requirements:

  1. Record type T_Float contains the following component:

    1. F, a floating-point type.

  2. Record type T_Mixed is derived from the T_Float type.

    1. T_Mixed extends T_Float with the following component:

      1. I, an integer component.

    2. Both components must be numerically synchronized:

      • For example, if the floating-point component contains the value 2.0, the value of the integer component must be 2.

      • In order to simplify the implementation, you can simply use Integer (F) to convert a floating-point variable F to integer.

  3. Function Init returns an object of the corresponding type (T_Float or T_Mixed).

    1. For each type, two versions of Init must be declared:

      1. one with a floating-point input parameter,

      2. another with an integer input parameter.

    2. The parameter to Init is used to initialize the record components.

  4. Function Image returns a string for the components of the record type.

    1. In case of the Image function for the T_Float type, the string must have the format "{ F =>  <float value> }".

      • For example, the call Image (T_Float'(Init (8.0)))) should return the string "{ F =>  8.00000E+00 }".

    2. In case of the Image function for the T_Mixed type, the string must have the format "{ F =>  <float value>, I => <integer value> }".

      • For example, the call Image (T_Mixed'(Init (8.0)))) should return the string "{ F =>  8.00000E+00, I =>  8 }".

package Type_Extensions is -- Create declaration of T_Float type! type T_Float is null record; -- function Init ... -- function Image ... -- Create declaration of T_Mixed type! type T_Mixed is null record; end Type_Extensions;
package body Type_Extensions is end Type_Extensions;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Type_Extensions; use Type_Extensions; procedure Main is type Test_Case_Index is (Type_Extension_Chk); procedure Check (TC : Test_Case_Index) is F1, F2 : T_Float; M1, M2 : T_Mixed; begin case TC is when Type_Extension_Chk => F1 := Init (2.0); F2 := Init (3); M1 := Init (4.0); M2 := Init (5); if M2 in T_Float'Class then Put_Line ("T_Mixed is in T_Float'Class as expected"); end if; Put_Line ("F1: " & Image (F1)); Put_Line ("F2: " & Image (F2)); Put_Line ("M1: " & Image (M1)); Put_Line ("M2: " & Image (M2)); end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;

Online Store

Goal: create an online store for the members of an association.

Steps:

  1. Implement the Online_Store package.

    1. Declare the Member type.

    2. Declare the Full_Member type.

    3. Implement the Get_Status function for the Member type.

    4. Implement the Get_Price function for the Member type.

    5. Implement the Get_Status function for the Full_Member type.

    6. Implement the Get_Price function for the Full_Member type.

  2. Implement the Online_Store.Tests child package.

    1. Implement the Simple_Test procedure.

Requirements:

  1. Package Online_Store implements an online store application for the members of an association.

    1. In this association, members can have one of the following status:

      • associate member, or

      • full member.

  2. Function Get_Price returns the correct price of an item.

    1. Associate members must pay the full price when they buy items from the online store.

    2. Full members can get a discount.

      1. The discount rate can be different for each full member — depending on factors that are irrelevant for this exercise.

  3. Package Online_Store has following types:

    1. Percentage type, which represents a percentage ranging from 0.0 to 1.0.

    2. Member type for associate members containing following components:

      • Start, which indicates the starting year of the membership.

        • This information is common for both associate and full members.

        • You can use the Year_Number type from the standard Ada.Calendar package for this component.

    3. Full_Member type for full members.

      1. This type must extend the Member type above.

      2. It contains the following additional component:

        • Discount, which indicates the discount rate that the full member gets in the online store.

          • This component must be of Percentage type.

  4. For the Member and Full_Member types, you must implement the following functions:

    1. Get_Status, which returns a string with the membership status.

      • The string must be "Associate Member" or "Full Member", respectively.

    2. Get_Price, which returns the adapted price of an item — indicating the actual due amount.

      • For example, for a full member with a 10% discount rate, the actual due amount of an item with a price of 100.00 is 90.00.

      • Associated members don't get a discount, so they always pay the full price.

  5. Procedure Simple_Test (from the Online_Store.Tests package) is used for testing.

    1. Based on a list of members that bought on the online store and the corresponding full price of the item, Simple_Test must display information about each member and the actual due amount after discounts.

    2. Information about the members must be displayed in the following format:

      Member # <number>
      Status: <status>
      Since:  <year>
      Due Amount:  <value>
      --------
      
    3. For this exercise, Simple_Test must use the following list:

      #

      Membership status

      Start (year)

      Discount

      Full Price

      1

      Associate

      2010

      N/A

      250.00

      2

      Full

      1998

      10.0 %

      160.00

      3

      Full

      1987

      20.0 %

      400.00

      4

      Associate

      2013

      N/A

      110.00

    4. In order to pass the tests, the information displayed by a call to Simple_Test must conform to the format described above.

      • You can find another example in the remarks below.

Remarks:

  1. In previous labs, we could have implemented a simplified version of the system described above by simply using an enumeration type to specify the membership status. For example:

    type Member_Status is (Associate_Member, Full_Member);
    
    1. In this case, the Get_Price function would then evaluate the membership status and adapt the item price — assuming a fixed discount rate for all full members. This could be the corresponding function declaration:

      type Amount is delta 10.0**(-2) digits 10;
      
      function Get_Price (M : Member_Status;
                          P : Amount) return Amount;
      
    2. In this exercise, however, we'll use type extension to represent the membership status in our application.

  2. For the procedure Simple_Test, let's consider the following list of members as an example:

    #

    Membership status

    Start (year)

    Discount

    Full Price

    1

    Associate

    2002

    N/A

    100.00

    2

    Full

    2005

    10.0 %

    100.00

    • For this list, the test procedure displays the following information (in this exact format):

      Member # 1
      Status: Associate Member
      Since:  2002
      Due Amount:  100.00
      --------
      Member # 2
      Status: Full Member
      Since:  2005
      Due Amount:  90.00
      --------
      
    • Here, although both members had the same full price (as indicated by the last column), member #2 gets a reduced due amount of 90.00 because of the full membership status.

with Ada.Calendar; use Ada.Calendar; package Online_Store is type Amount is delta 10.0**(-2) digits 10; subtype Percentage is Amount range 0.0 .. 1.0; -- Create declaration of Member type! -- -- You can use Year_Number from Ada.Calendar for the membership -- starting year. -- type Member is null record; function Get_Status (M : Member) return String; function Get_Price (M : Member; P : Amount) return Amount; -- Create declaration of Full_Member type! -- -- Use the Percentage type for storing the membership discount. -- type Full_Member is null record; function Get_Status (M : Full_Member) return String; function Get_Price (M : Full_Member; P : Amount) return Amount; end Online_Store;
package body Online_Store is function Get_Status (M : Member) return String is (""); function Get_Status (M : Full_Member) return String is (""); function Get_Price (M : Member; P : Amount) return Amount is (0.0); function Get_Price (M : Full_Member; P : Amount) return Amount is (0.0); end Online_Store;
package Online_Store.Tests is procedure Simple_Test; end Online_Store.Tests;
with Ada.Text_IO; use Ada.Text_IO; package body Online_Store.Tests is procedure Simple_Test is begin null; end Simple_Test; end Online_Store.Tests;
with Ada.Command_Line; use Ada.Command_Line; with Ada.Text_IO; use Ada.Text_IO; with Online_Store; use Online_Store; with Online_Store.Tests; use Online_Store.Tests; procedure Main is type Test_Case_Index is (Type_Chk, Unit_Test_Chk); procedure Check (TC : Test_Case_Index) is function Result_Image (Result : Boolean) return String is (if Result then "OK" else "not OK"); begin case TC is when Type_Chk => declare AM : constant Member := (Start => 2002); FM : constant Full_Member := (Start => 1990, Discount => 0.2); begin Put_Line ("Testing Status of Associate Member Type => " & Result_Image (AM.Get_Status = "Associate Member")); Put_Line ("Testing Status of Full Member Type => " & Result_Image (FM.Get_Status = "Full Member")); Put_Line ("Testing Discount of Associate Member Type => " & Result_Image (AM.Get_Price (100.0) = 100.0)); Put_Line ("Testing Discount of Full Member Type => " & Result_Image (FM.Get_Price (100.0) = 80.0)); end; when Unit_Test_Chk => Simple_Test; end case; end Check; begin if Argument_Count < 1 then Put_Line ("ERROR: missing arguments! Exiting..."); return; elsif Argument_Count > 1 then Put_Line ("Ignoring additional arguments..."); end if; Check (Test_Case_Index'Value (Argument (1))); end Main;