program SetGet;

{
*********************************************************************
*                                                                   *
* In the unit SetGetSub.pas we have two variables, one with a       *
* Getter, (read only) and one with a getter and setter. The read    *
* only variable xc is a count of how many times the settable        *
* has changed since the last read. Different versions of the        *
* Getters and setters are shown showing the different stages of     *
* a mythical development.                                           *
*                                                                   *
* Try1 is the classical method that we all use.                     *
*                                                                   *
* Try2 achieves the same using setters and getters. Because we are  *
* not using units it is still not safe, but should ease maintenance *
*                                                                   *
* Try 3 shows how Try 2 might evolve. This would be an easy         *
* development but had we used the methods in try 1 it would be      *
* much harder as we would have to find every occurrance of          *
* assigning the variable and edit it. Even with Try2, though we     *
* really still need to do this because we (or some other developer) *
* might have used direct assignment instead of using the function.  *
*                                                                   *
* Try 4 is just like try 2 but split over 2 units. The big          *
* advantage here is that direct access is no longer possible        *
* outside the second unit.                                          *
*                                                                   *
* Try 5 is just like try 3, except that we now know that no-one     *
* could have directly accessthe variable outside the unit, so we    *
* don't have to try and find every unit and every occurrance where  *
* the variable might have been updated directly.                    *
*                                                                   *
* Note that in tries 2 and 4 the code generated after optimisation  *
* is almost identical to that generated in try 1. Compare           *
* procedures Try1, Try2 and Try4.                                   *
*                                                                   *
*********************************************************************
}

{$NOSHADOW}
{ $WG}                     {global Warnings off}

Device = mega1280, VCC=5;
{ $BOOTRST $0F000}         {Reset Jump to $0F000}

Import SysTick;

From System Import ;


Define
  ProcClock      = 16000000;       {Hertz}
  SysTick        = 10;             {msec}
  StackSize      = $0064, iData;
  FrameSize      = $0064, iData;
  
uses
  SetGetSub;

Implementation

{$IDATA}

{--------------------------------------------------------------}
{ Type Declarations }

type


{--------------------------------------------------------------}
{ Const Declarations }

{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}


{--------------------------------------------------------------}
{ functions }

var
  x1 : byte;
  xc1 : byte;
  bCount : byte;
  ix : byte;

//----------- Try 1 ----------------

procedure Try1; // not OO
begin
  x1 := 3; // how many times have we read this?
end;

//------------ Try 2 - a better way? ---------------------------------

procedure Set2x1( NewVal : byte ); // Setter
begin
  x1 := NewVal;
  {
    Inititially we don't care, so why put it in a function?
    Well, we don't know if we might care later, and rather
    than have to search for every assignement later, it
    might be better to always assign via a setter now
  }
end;

function Get2x1 : byte; // getter
begin
  return( x1 );
end;

procedure Try2;
begin
  Set2x1( 3 );
  ix := Get2x1;
  // x1 := 4; // uncommenting this line will compile OK.
end;

// --------------- Try 3 - how it evolves

procedure Set3x1( NewVal : byte );
begin
{
  here we are 'doing the right thing'. We keep a count of every time we
  assign a value. The problem is that we could change x1 anywhere without
  changing the count. Furthermore we can change xc anywhere. This makes
  maintenance an issue.
}
  x1 := NewVal;
  inc( xc1 );
end;

function Get3xc1 : byte;
var
  Result : byte;
begin
{
  we now have a getter for xc1 that automatically resets the count.
  This makes code later much more readable. Unfortunately, xc is still
  not safe
}
  Result := xc1;
  xc1 := 0;
  return( Result );
end;

procedure Try3;
begin
  Set3x1( 3 );  // Now more complex and will no longer be inline.
  ix := Get2x1; // the getter has not changed between versions and will still be inline
  // x1 := 4; // uncommenting this line will compile OK, but changes x1 without changing the count. This is BAD!
  Bcount := Get3xc1;
end;

// -------------- Try 4 - putting var in a subunit

procedure Try4;
begin
{
  We have put the variable into a unit. This means control is
  much tighter. This is similar to Try2 in al other respects.
  We still are not counting accesses. Not that any attempt to
  access the variable directly now fails
}

  Set4x2( 3 );
  ix := Get4x2;
  // x2 := 4; // uncommenting this line will not compile - showing that all handling of this var is restricted to the unit
              // So we have only one place to maintain this variable. When you look at the asm file Set4x2 and Get4x2
              // will no longer exist and will be replaced by inline code after optimisation
end;

// -------------- Try 5 - Adding the counter into the subunit

procedure Try5;
begin
  Set5x2( 3 );  // No longer inline...
  ix := Get4x2; // routine has not changed from Try 4, and will still be inline
  // x2 := 4; // uncommenting this line will not compile - as in Try4
  Bcount := Get5xc2;
end;

{--------------------------------------------------------------}
{ Main Program }
{$IDATA}

begin

  Try1;
  Try2;
  Try3;
  Try4;
  Try5;
  EnableInts;
  loop


  endloop;
end SetGet.

